LookingGlass Documentation

An extremely low latency KVMFR (KVM FrameRelay) implementation for guests with VGA PCI Passthrough.

5,741 stars C C 32 files Β· ~26,824 tokens #kvm-framerelay#kvmfr#qemu-kvm#vga-pci-passthrough
RAW Doc

Technical Documentation: gnif/LookingGlass

ℹ️ Provenance: Multi-Tier Ingestion Β· CodeWiki Reference

Overview (`README.md`)

Looking Glass

Looking Glass lets you use a Windows virtual machine from Linux with very low
display and input latency. The current recommended setup uses the Looking Glass
Indirect Display Driver (IDD) in the Windows guest and the Looking Glass Client
on the Linux host.

Start here

The Linux client is currently distributed as source code and must be built
before it can be installed. The end-user guide covers the complete process:

  1. Build the Linux client.
  2. Configure shared memory for the virtual machine.
  3. Install the Looking Glass IDD in Windows.
  4. Install and run the client.

See the Looking Glass documentation for the
current requirements and setup guide.

Source archives

❕❕❕ IMPORTANT ❕❕❕

This project contains submodules that must be checked out if building from the
git repository! If you are not a developer and just want to compile Looking
Glass, please download the source archive from the website instead:

https://looking-glass.io/downloads

Source code for the documentation can be found in the doc directory.

You may view this locally as HTML by running make html with python3-sphinx
and python3-sphinx-rtd-theme installed.


Overview (`profile/README.md`)

##This directory contains programs for LG performance profiling.

###Directories:

  • client - dummy client that profiles the host application's performance.

Overview (`client/tests/README.md`)

Client rendering tests

These gtests run the production client with the synthetic test transport,
capture the fully composed framebuffer immediately before presentation, and
compare every pixel with an independent reference implementation.

The default CTest entry starts an isolated headless Weston compositor using
Mesa software rendering. It covers:

  • BGRA, RGBA, packed BGR32, RGB24, PQ RGBA10, and scRGB RGBA16F;
  • odd widths and 24-bit row pitches;
  • the Cartesian matrix of every format with full-frame, moving old/new-box,
    overlapping, maximum-count, invalid, null, and zero-area damage;
  • HDR-to-SDR transfer, gamut conversion, and tone mapping.

When run on a color-managed Wayland compositor with a compatible EGL surface,
the same tests validate native RGB10A2 or FP16 output. Native PQ tests also
check the requested BT.2020 image description, reference white, mastering
luminance, MaxCLL, and MaxFALL in the client log.

Building and running

sh
cmake -S client -B client/build \
  -DENABLE_TESTS=ON
cmake --build client/build
ctest --test-dir client/build --output-on-failure \
  -R render-tests

GoogleTest and Weston are required when ENABLE_TESTS is enabled.
Failed cases retain their capture and client log under /tmp and print the
artifact paths.

To exercise native HDR on the current Wayland session instead of the headless
SDR compositor:

sh
client/build/tests/render-tests \
  --gtest_filter='*rgba10*:*rgba16f*'

Framebuffer readback verifies the signal produced by Looking Glass. Verifying
a compositor's scanout and a physical panel's luminance remains a separate
hardware test.


Doc Audio (`doc/audio.rst`)

.. _client_audio:

Audio and microphone
####################

The client selects audio independently from video and input. The current LGMP
transport does not provide audio, so SPICE normally supplies it in an IDD
setup. Selecting SPICE as the primary video transport also uses its audio
provider.

.. warning::

Do not use Scream for a Looking Glass setup. Use the built-in classic SPICE
or USB audio path. Scream over IVSHMEM can also conflict with the shared
device used for Looking Glass frames.

Looking Glass offers two SPICE audio paths:

USB audio (recommended)
Presents an emulated Looking Glass USB Audio Class 2 device to Windows over
a SPICE USB channel. It supports stereo, quadraphonic, 5.1 and 7.1 playback
using 24-bit PCM at up to 192 kHz. It also provides asynchronous playback
feedback and a lower-latency clock relationship with supported Linux audio
backends. This path is enabled by default when it is available.

Classic SPICE audio
Uses a virtual guest sound card and SPICE playback and record channels.
QEMU limits it to stereo, 16-bit samples at 48 kHz. Use it as a compatibility
fallback when the emulated USB audio device is not available.

Set spice:audio=no to disable both paths.

.. _client_usb_audio:

USB audio setup

USB audio requires:

  • a client built with libusbredirparser-0.5 version 0.7.1 or newer;
  • at least one unused SPICE USB redirection channel in the VM; and
  • a working client playback backend.

For libvirt, add a USB redirection device:

.. code:: xml

In virt-manager, this is a USB Redirector device using the SPICE channel.
It is dedicated to the virtual Looking Glass audio device while USB audio is
active.

The emulated USB audio device is enabled by default. Its settings are:

.. code-block:: ini

[spice]
audio=yes
usbAudio=yes

Playback supports stereo, quadraphonic, 5.1 and 7.1 speaker layouts using
24-bit PCM at sample rates up to 192 kHz. Recording supports stereo at up to
192 kHz.

After the device connects, select the Looking Glass USB Audio speakers as the
Windows output device.

If USB audio could not be created at startup, the client falls back to classic
SPICE audio and logs the reason. A working USB audio device also requires the
SPICE USB redirection channel to connect; if the channel is absent, add it to
the VM rather than reinstalling the Windows endpoint.

Classic SPICE setup

Add an Intel HDA sound device and a SPICE audio backend to the VM as shown in
:ref:libvirt_spice_server, then select the classic path:

.. code-block:: ini

[spice]
audio=yes
usbAudio=no

QEMU's classic SPICE audio implementation exposes a fixed stereo format: two
channels, 16-bit samples at 48 kHz. Use the emulated USB audio device when
other sample rates, sample formats or channel layouts are required.

Microphone access

PipeWire supports playback and recording. The current PulseAudio backend does
not provide microphone recording. Press :kbd:ScrLk + :kbd:E to toggle
recording when it is available.

When a guest application opens the microphone, audio:micDefault controls
the response:

prompt
Ask before sending microphone audio. This is the default.

allow
Allow requests automatically.

deny
Refuse requests automatically.

Press :kbd:ScrLk + :kbd:C to cycle this policy. Keep
audio:micShowIndicator=yes to show when recording is active.

Latency settings

audio:periodSize requests the audio backend period in samples. The default
is 512; 0 requests a 10 ms period. Smaller values may reduce latency but also
make underruns more likely.

audio:latencyOffset applies only to classic SPICE audio. It adds safety
margin to the calculated minimum buffer; the default is 6 ms. Reduce it only
after confirming that classic SPICE playback remains free of dropouts under
load.

audio:resampler also applies only to classic SPICE audio. The default
auto setting chooses the appropriate path; the other choices are
libsamplerate and backend. The emulated USB audio device instead uses
feedback to adjust the Windows packet rate.

Set audio:debug=yes to log ring-buffer level, backend delay, clock feedback
and underrun or overrun counts. Disable it after diagnosis to keep the normal
log concise.


Doc Build (`doc/build.rst`)

.. _building:

Build the Linux client
######################

The Looking Glass Client is currently distributed as source code. Building it
is a normal part of installation, not an optional developer step. These
instructions require basic familiarity with a Linux shell.

.. _download_source:

Downloading

Visit the Looking Glass Download Page <https://looking-glass.io/downloads>__,
and download the stable version (Recommended).
You can also download a bleeding-edge version, or the latest RC version
during a Release Candidate cycle.

Developers can clone the source code repo with git.

.. code:: bash

git clone --recursive https://github.com/gnif/LookingGlass.git

.. warning::

Please only clone from Git if you're a developer, and know what you're
doing. Looking Glass requires git submodules that must be setup and updated
when building. Source code downloads from the website come bundled with the
necessary submodules.

.. note::

The current client, IDD and OBS plugin must come from the same Looking Glass
release. Bleeding-edge builds must be paired with their matching
bleeding-edge components. Legacy Host users must instead use the complete
matching B7 stack described in :ref:legacy_host_policy.

.. _build_client_section:

Client Application

.. _installing_build_dependencies:

Installing build dependencies

text
These required libraries and tools should be installed first.

.. note::

   The below list of dependencies is for Debian. A community maintained list of
   dependencies for other distributions for the current **stable** version of
   Looking Glass is maintained on the wiki at:
   https://looking-glass.io/wiki/Installation_on_other_distributions

.. _client_dependencies:

Required dependencies
^^^^^^^^^^^^^^^^^^^^^

..
   Editor note: Listed dependencies are Debian packages containing the
   required resources. All dependencies must be explicitly defined.
   Omitting required dependencies that happen to be pulled in via
   Depends: or Recommends: from another listed package is not allowed.
   All required packages must be listed.

-  ``cmake``
-  ``binutils``
-  ``gcc``, ``g++`` \| ``clang``
-  ``libegl-dev``
-  ``libgl-dev``
-  ``libgles-dev``
-  ``libfontconfig-dev``
-  ``libgmp-dev``
-  ``libspice-protocol-dev``
-  ``libxkbcommon-dev``
-  ``make``
-  ``nettle-dev``
-  ``pkg-config``

.. _client_deps_may_be_disabled:

May be disabled
<<<<<<<<<<<<<<<

These dependencies are required by default, but may be omitted if their
feature is disabled when running :ref:`cmake <client_building>`.

-  Disable with ``cmake -DENABLE_BACKTRACE=no ..``

   -  ``libdw-dev``
   -  ``libunwind-dev``

-  Disable with ``cmake -DENABLE_X11=no ..``

   -  ``libx11-dev``
   -  ``libxfixes-dev``
   -  ``libxi-dev``
   -  ``libxinerama-dev``
   -  ``libxss-dev``
   -  ``libxcursor-dev``
   -  ``libxpresent-dev``
   -  ``libxrandr-dev``

-  Disable with ``cmake -DENABLE_WAYLAND=no ..``

   -  ``libwayland-bin``
   -  ``libwayland-dev``

-  Disable all audio support with ``cmake -DENABLE_AUDIO=no ..``

   -  ``libpipewire-0.3-dev``
   -  ``libpulse-dev``
   -  ``libsamplerate0-dev``
   -  ``libusbredirparser-dev``

-  Disable with ``cmake -DENABLE_PIPEWIRE=no ..``

   -  ``libpipewire-0.3-dev``

-  Disable with ``cmake -DENABLE_PULSEAUDIO=no ..``

   -  ``libpulse-dev``

-  Disable USB audio with ``cmake -DENABLE_USB_AUDIO=no ..``

   -  ``libusbredirparser-dev`` version 0.7.1 or newer

``libsamplerate0-dev`` is required whenever audio support remains enabled.

.. _client_deps_recommended:

Recommended
<<<<<<<<<<<

-  ``fonts-dejavu-core`` (This is the default UI font, but a random font will
   be chosen if not available).

.. _client_fetching_with_apt:

Fetching with APT
^^^^^^^^^^^^^^^^^

You can fetch these dependencies with the following command:

.. warning::

   The command below builds both PipeWire and PulseAudio playback backends.
   Omit one development package only when also disabling its backend in CMake.
   Microphone recording requires PipeWire; the current PulseAudio backend is
   playback-only.

.. code:: bash

   apt-get install binutils cmake make fonts-dejavu-core libdw-dev \
   libfontconfig-dev libgmp-dev libunwind-dev gcc g++ pkg-config \
   libegl-dev libgl-dev libgles-dev libspice-protocol-dev nettle-dev \
   libx11-dev libxcursor-dev libxfixes-dev libxi-dev libxinerama-dev \
   libxpresent-dev libxrandr-dev libxss-dev libxkbcommon-dev \
   libwayland-bin libwayland-dev \
   libpipewire-0.3-dev libpulse-dev libsamplerate0-dev \
   libusbredirparser-dev

You may omit some dependencies if you disable the feature which requires them
when running :ref:`cmake <client_building>`.
(See :ref:`client_deps_may_be_disabled`)

.. _client_building:

Building
~~~~~~~~

If you've downloaded the source code as a zip file, simply unzip and ``cd``
into the new directory. If you've cloned the repo with ``git``, then ``cd``
into the *LookingGlass* directory.

.. code:: bash

   mkdir client/build
   cd client/build
   cmake ../
   make

This will build the ``looking-glass-client`` binary, which is used to display
frames from the guest. It also produces ``looking-glass-client.debug``. Keep
this file with the matching binary to obtain source locations in crash stack
traces. The install target places it in the standard ``bin/.debug`` location
automatically.

You can then :ref:`continue installing Looking Glass <client_install>`, or run
it directly from the build directory:

.. code:: bash

   ./looking-glass-client

.. seealso::

   -  :ref:`Client installation <client_install>`
   -  :ref:`Client usage <client_usage>`

.. note::

   For users running GNOME on Wayland, you may want to enable ``libdecor`` when
   building.

   .. code:: bash

      cmake -DENABLE_LIBDECOR=ON ../

   For details, see :ref:`the FAQ <gnome_wayland_decorations>`.

.. note::

   The most common compile error is related to backtrace support. Try disabling
   this when building:

   .. code:: bash

      cmake -DENABLE_BACKTRACE=0 ../

   If you disable this and need support for a crash, use ``gdb`` to obtain a
   backtrace manually.

---

### Doc Build Host (`doc/build_host.rst`)

.. _host_building:

Legacy Host Application build
#############################

.. warning::

   The Host Application is a legacy server application. New installations should
   use the prebuilt :doc:`Looking Glass IDD <install_idd>`. These build
   instructions are retained for the complete matching B7 stack described in
   :ref:`legacy_host_policy`.

.. note::

   `Host` in this context refers to the `Looking Glass (LG) host server application`,
   to which the LG client connects to, it thus does not refer to the `host OS`!

   A common setup is to have a `host OS` running a `guest VM`. In such a setup
   the `client application` runs on the `host OS`; and the `host application`
   on the `guest VM`.

   The term `Host application` was chosen over `Guest application`, because LG
   can be run in a VM to VM configuration, in which case both Host Application and
   Client Application are run inside VM Guests.

These instructions help you build the host yourself from the
:ref:`downloaded source code <download_source>`.

.. warning::
   :name: dont-build-the-host

   Building the host from source code is not recommended for most purposes,
   and should only be attempted by users who are prepared to handle issues
   on their own. Please download the pre-built binary installers from
   https://looking-glass.io/downloads for stability, and increased support.

   .. note::

      The pre-built binaries also include NvFBC support built in, which is
      only available to current Nvidia SDK license holders, and cannot
      be enabled when building the host without also having a license.

   (`link <#dont-build-the-host>`_)

.. _host_win_on_win:

For Windows on Windows
~~~~~~~~~~~~~~~~~~~~~~

1. Download and install msys2 x86_64 from
   `http://www.msys2.org/ <http://www.msys2.org/>`__ following the setup
   instructions provided

2. Run the MSYS2 shell

3. Download build dependencies with pacman

.. code:: bash

   pacman -Fy
   pacman -Sy git make mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake

4. Change directory to the source tree with ``cd``

5. Configure the project and build it

.. code:: bash

   mkdir host/build
   cd host/build
   cmake -G "MSYS Makefiles" ..
   make

.. _host_linux_on_linux:

For Linux on Linux
~~~~~~~~~~~~~~~~~~

Make a ``host/build`` directory, then run ``cmake``

.. code:: bash

   mkdir host/build
   cd host/build
   cmake ..
   make

.. _host_win_cross_on_linux:

For Windows cross compiling on Linux

Like :ref:host_linux_on_linux, but using the mingw64 toolchain to
cross-compile a Windows .exe file.

.. code:: bash

mkdir host/build
cd host/build
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-mingw64.cmake ..
make

.. _host_build_installer:

Building the Windows installer

text
1. :ref:`Build <host_win_cross_on_linux>` the host on Linux.

2. Install ``nsis``

.. code:: bash

   apt-get install nsis

3. Use ``makensis`` to build the installer.

.. code:: bash

   cd host/build/platform/Windows
   makensis installer.nsi

.. _host_questions:

This will build ``looking-glass-host-setup.exe`` under
``host/build/platform/Windows/looking-glass-host-setup.exe``

.. seealso::

   :ref:`Installing the Host <host_install>`

---

### Doc Credits (`doc/credits.rst`)

.. _looking_glass_team:

Looking Glass team
##################

A list of the wonderful people who make this possible.

.. _lg_devs:

Developers
------------------

* gnif (Geoffrey McRae)
* quantum (Guanzhong Chen)
* xyene (Tudor Brindus)
* spencercw (Chris Spencer)

.. _lg_documentation_guys:

Documentation
-------------

* JJRcop (Jonathan Rubenstein)

---

### Doc Display (`doc/display.rst`)

.. _client_display:

Display and image quality
#########################

The EGL renderer is the supported client renderer and is selected
automatically. The older OpenGL renderer is deprecated, does not provide direct
DMA imports or native HDR, and should only be used to diagnose a compatibility
problem.

Wayland and X11 are both built by default. Automatic selection prefers Wayland
when ``WAYLAND_DISPLAY`` is set, then X11 when ``DISPLAY`` is set. To force X11
from a Wayland session for diagnosis, preserve ``DISPLAY`` and unset
``WAYLAND_DISPLAY`` for the client process.

Window and guest resolution
---------------------------

With the IDD, ``win:setGuestRes=yes`` asks Windows to match the client viewport
when its size changes. Press :kbd:`ScrLk` + :kbd:`=` to request the current
size immediately. The IDD creates this as its dynamic ExtraMode using the
default refresh configured in the IDD helper.

If a requested resolution does not fit in IVSHMEM, the IDD refuses it and the
helper reports the required size. See :ref:`libvirt_determining_memory`.

Useful window options include:

``win:autoResize``
   Resize the client window when the guest resolution changes.

``win:keepAspect``
   Preserve the guest aspect ratio while resizing.

``win:fullScreen``
   Start in borderless full-screen mode.

``win:rotate``
   Rotate the image by 0, 90, 180 or 270 degrees.

Scaling and filters
-------------------

The overlay's **EGL filters** page controls scaling, sharpening and custom
processing. Filters run from top to bottom and can be reordered. Save useful
combinations as named presets, then select one at startup with ``egl:preset``.

The built-in filters include:

* a configurable downscaler;
* AMD FidelityFX Super Resolution (FSR); and
* AMD FidelityFX Contrast Adaptive Sharpening (CAS).

The ``egl:scale`` option selects automatic, nearest-neighbor or linear
scaling when a filter does not provide the required scaling. Additional
mpv-style GLSL shaders may be loaded from ``eglFilter:glslPath``. The
`Anime4K <https://github.com/bloc97/Anime4K>`_ project provides compatible
GLSL filters.

.. _client_hdr:

HDR
---

The IDD exposes HDR only when the Windows runtime provides the required IddCx
interfaces and the IDD is using a hardware render adapter. This normally means
a compatible Windows 11 guest. Windows 10 and IDD software processing remain
on the SDR path.

Native HDR output on Linux requires all of the following:

* the EGL renderer;
* a Wayland compositor with ``color-management-v1`` support;
* an HDR-capable monitor and output configuration; and
* a host graphics driver that can present the required color format.

With ``egl:mapHDRtoSDR=yes`` the client tone-maps HDR frames for an SDR desktop.
Use ``egl:peakLuminance`` to describe the SDR display target and
``egl:maxCLL`` to limit the assumed content light level.

X11 presentation is SDR. The EGL renderer tone-maps HDR to SDR there by
default. Native Wayland PQ output also requires compositor support for ST 2084
and BT.2020, while scRGB requires compositor scRGB support.

Presentation latency
--------------------

The defaults favor low latency rather than conventional buffered rendering.
Do not enable ``egl:vsync`` or ``egl:doubleBuffer`` merely to chase a reported
frame-rate number; either can add presentation delay. Use the timing graphs to
confirm the result on the actual compositor and GPU.

``win:jitRender`` delays rendering toward the expected presentation deadline.
It can reduce the age of a frame at display time, but depends on stable timing.
Leave it disabled while diagnosing stalls or an unstable refresh cadence.

---

### Doc Faq (`doc/faq.rst`)

Frequently asked questions
##########################

General
-------

.. _how_does_looking_glass_work:

How does Looking Glass work?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Windows IDD creates a virtual monitor and places completed frames in an
IVSHMEM region shared with Linux. The client imports the newest frame, renders
it and returns input through the available transport. The image is not encoded
as a video stream, which avoids codec latency and quality loss.

See :doc:`overview` for the current components. A detailed video explanation
is also available at https://www.youtube.com/watch?v=U44lihtNVVM.

.. _can_i_feed_the_vm_directly_into_obs:

Can I feed the VM directly into OBS?

Yes. The :doc:OBS plugin <obs> is an independent frame consumer and does not
capture the client window.

.. _why_is_my_ups_so_low:

Why is UPS lower than the guest refresh rate?

text
UPS counts frames delivered to that consumer, not every frame Windows may
render. The IDD publishes to the deadline requested by the fastest active
client and can skip guest frames that have already been superseded. This saves
memory bandwidth without deliberately adding a frame of latency.

If UPS is below the active consumer's requested rate, use
:ref:`client_performance` to locate the slow stage. High resolution, software
processing, memory bandwidth, host scheduling and compositor presentation can
all impose a lower limit.

.. _is_my_gpu_supported:

Is a passed-through GPU required?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

No. The IDD can create an SDR display using software processing when it cannot
use a Windows render adapter. A hardware adapter is strongly recommended for
lower latency, higher refresh rates, HDR, and cadence scheduling.

The Linux client still needs an EGL-capable host graphics driver. Direct
DMA-BUF import depends on the host GPU and driver; the client falls back to a
copy when it is unavailable.

.. _why_do_i_need_spice_if_i_dont_want_a_spice_display_device:

Do I need SPICE?
~~~~~~~~~~~~~~~~

SPICE is not required for the primary IDD video or direct input paths. It is
still useful for clipboard, audio, input fallback and automatic video fallback.
These services are selected independently.

Set ``spice:enable=no`` or use ``-s`` to disable SPICE completely. Disable an
individual service with ``spice:input``, ``spice:clipboard`` or
``spice:audio`` instead when the other services are still wanted.

.. _where_is_the_host_application_for_linux:

Which application runs on Linux?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Looking Glass Client runs on the Linux host operating system. The IDD runs
inside the Windows guest. The older product named the **Host Application** is a
legacy Windows server; β€œHost” in that name does not mean the Linux host OS.

Input and window system
-----------------------

.. _gnome_wayland_decorations:

Why is there no title bar on GNOME Wayland?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GNOME does not implement the standard Wayland server-side decoration
protocol. Build Looking Glass with libdecor support:

.. code:: bash

   cmake -DENABLE_LIBDECOR=ON ../

Install ``libdecor-0-dev`` first on Debian-based systems. Alternatively, hold
the Super key and right-click the window to use the compositor's move and
resize menu.

.. _the_mouse_is_jumpy_slow_laggy_when_using_spice:

Why is SPICE fallback mouse movement different?

The IDD's direct input path uses absolute positioning for normal desktop use
and relative movement in capture mode. SPICE input is relative-only, so guest
mouse acceleration can change its feel or cause temporary position error.

Use the direct IDD input path when available. For a game, use capture mode and
consider input:rawMouse=yes.

.. _the_cursor_position_doesnt_update_until_i_click:

Should I add a virtual tablet?

text
No. Looking Glass does not require an additional virtio tablet, mouse or
keyboard. Direct IDD input provides its own absolute and relative devices, and
SPICE fallback uses the VM's default PS/2 input devices.

Audio
-----

Does Looking Glass support microphone input and surround sound?

Yes. The recommended emulated USB Audio 2.0 device provides stereo,
quadraphonic, 5.1 and 7.1 playback plus stereo recording at rates up to
192 kHz. Classic SPICE audio also provides playback and recording. Client
microphone recording currently requires the PipeWire backend. See
:doc:audio.

Legacy Host Application

The sections below apply only to the legacy Windows Host Application. New
installations should use the IDD. See :ref:legacy_host_policy.

.. _faq_host:

Where is the legacy Host log?

text
The application log is:

``%ProgramData%\Looking Glass (host)\looking-glass-host.txt``

The service log is:

``%ProgramData%\Looking Glass (host)\looking-glass-host-service.txt``

.. _faq_host_admin_privs:

Why does the legacy Host require administrator privileges?

The legacy capture APIs use privileged functions for GPU scheduling, NvFBC
setup and secure-desktop capture. The installer runs it as a Windows service
under the SYSTEM account. This is not how the current IDD is configured.

.. _nvfbc_nvidia_capture_api_doesnt_work:

Why does NvFBC not work?

text
NvFBC is a legacy Host capture method and requires supported NVIDIA hardware
and SDK licensing. It is not part of the IDD path.

.. _the_screen_stops_updating_when_left_idle_for_a_time:

Why does a legacy captured display stop when idle?

Windows may turn off the physical or dummy display captured by the legacy
Host. Disable display sleep for that monitor. The IDD virtual-monitor path does
not require a physical display.

.. _a_note_about_ivshmem_and_scream_audio:

Can Scream and Looking Glass share IVSHMEM?

text
Do not use Scream with Looking Glass. Use the built-in classic SPICE or USB
audio path instead. In particular, Scream's IVSHMEM transport can select or
interfere with the shared device used for Looking Glass frames.

Technical details
-----------------

.. toctree::
   :maxdepth: 1

   tech_faq

---

### Doc Host Usage (`doc/host_usage.rst`)

.. _host_usage:

Legacy Host Application configuration
#####################################

.. warning::

   This page applies only to the legacy Windows Host Application. New
   installations should use the IDD. B7 is the last recommended complete stack
   when non-capture mouse input through the Host Application is required.

The legacy Host normally selects a compatible frame path automatically. Its
persistent configuration file is:

``C:\Program Files\Looking Glass (host)\looking-glass-host.ini``

Use options from the same release as the Host binary. Do not copy a current
Host configuration into B7 or combine a B7 Host with a current client.

.. _host_capture:

Capture interface
-----------------

The legacy Host captures an existing Windows display through Desktop
Duplication or NvFBC. It does not use Windows Graphics Capture. Select an
interface only when automatic selection fails:

.. code-block:: ini

   [app]
   capture=d12

.. _host_capture_d12:

D12
   The preferred Direct3D 12 Desktop Duplication path on supported systems. It
   can copy directly toward shared memory and supports damage tracking.

.. _host_capture_dxgi:

DXGI
   The Direct3D 11 Desktop Duplication compatibility path. It may require an
   additional staging copy and can show cursor-related capture jitter.

.. _host_capture_nvfbc:

NvFBC
   An NVIDIA SDK path available only with supported hardware and licensing.
   It is not required by the IDD or the normal legacy D12 path.

The exact capture-interface options can change between releases. Consult the
binary's help and the configuration comments supplied with that release.

.. _host_select_ivshmem:

Select an IVSHMEM device
------------------------

The legacy Host selects the first IVSHMEM device by default. When the VM has
more than one, ``os:shmDevice`` selects by zero-based device order:

.. code-block:: ini

   [os]
   shmDevice=1

Check the Host log after changing it; the selected device is marked with an
asterisk. This option is for the legacy Host and is not an IDD helper setting.

.. _host_downsampling:

Downsampling
------------

The legacy Host can reduce a captured resolution before transport. Rules use
``source:target`` syntax and may match resolutions greater than a threshold:

.. code-block:: ini

   ; Downsample exactly 3840x2160 to 1920x1080
   downsample=3840x2160:1920x1080

   ; Downsample anything larger than 1920x1080
   downsample=>1920x1080:1920x1080

This saves transport bandwidth but does not reduce the guest application's
rendering work. IDD users should request the required virtual monitor
resolution instead.

---

### Doc Idd Configuration (`doc/idd_configuration.rst`)

.. _idd_configuration:

Configure the IDD
#################

Right-click the **Looking Glass (IDD)** icon in the Windows notification area
and select **Open configuration**. The icon and its tooltip also show whether
the driver is using GPU acceleration or software processing.

Display modes
-------------

The mode list controls the resolutions and refresh rates that Windows may use
for the Looking Glass monitor.

* Select a mode to edit its width, height or refresh rate, then select
  **Update**.
* Select **<add new>**, enter a mode in the fields below the list and select
  **Update** to add it.
* Select **Delete** to remove the selected mode.
* Select **Load default** to replace the working list with the standard modes.
* Enable **prefer** on the mode that Windows should prefer. Only one mode can
  be preferred.

Refresh rates may contain up to three decimal places. For example, enter
``119.970`` rather than rounding it to 120 Hz. Accepted values range from
23.900 Hz to 1000.000 Hz. Width may range from 640 to 16384 pixels and height
from 480 to 16384 pixels.

Edits to the mode list are not applied immediately. Select **Save & reload
driver** when the list is ready. This saves the list, removes and recreates the
virtual monitor, and can make the display blink briefly. **Revert** discards
unsaved mode and default-refresh changes.

Default refresh
---------------

**Default refresh** is used when the client asks the IDD to create a dynamic
resolution. It also supplies the refresh rate when **Load default** rebuilds
the standard mode list.

Changing this value does not rewrite refresh rates already saved in the normal
mode list. On reload, an existing dynamic mode keeps its resolution and adopts
the new default refresh rate.

The client option ``win:setGuestRes`` enables automatic dynamic resolution
requests when the client window changes size. The default is enabled when the
server in the guest supports it. Press the client's escape key together with
``=`` to request the current window resolution manually.

Preferences
-----------

Make LG the only monitor
   Makes the Looking Glass display the only active Windows monitor. This is
   enabled by default and the helper restores the topology when required.
   Disable it if you intentionally use other guest displays at the same time.
   Disabling it stops future enforcement but does not automatically restore
   displays that Windows has already disabled.

Disable no GPU warning
   Suppresses the notification shown when the IDD has fallen back to software
   processing. It does not enable GPU acceleration or change the active
   adapter.

Force full direct frame copies
   Works around GPU drivers that corrupt partial D3D12 copies into the shared
   transport heap. When enabled, the GPU copies every direct frame in full;
   readback/indirect transfers continue using partial damage copies. This can
   substantially increase GPU and shared-memory bandwidth, so leave it
   disabled unless you encounter corruption. Changing it requests a driver
   reload.

Force indirect copy
   Disables direct D3D12 access to the shared transport heap and instead
   copies each frame through a CPU-mapped readback resource. Enable this only
   to work around a GPU driver that corrupts direct transport writes: it adds
   a CPU copy and significantly reduces throughput. It takes precedence over
   the direct-copy preference and requests a driver reload when changed.

Unlike mode-list edits, preference checkboxes are saved when clicked.

Software processing
-------------------

If no suitable Windows render adapter is available, the IDD can use software
processing. This provides a display but is slower, cannot provide predictable
high-rate cadence and is limited to SDR. Check the IDD log to see which render
adapter was selected and whether software processing is active.

Modes that do not fit in shared memory
--------------------------------------

At startup the IDD removes modes that cannot fit in the configured IVSHMEM
region. If every suitable mode is filtered, the monitor cannot start. A
dynamic resolution request that is too large is refused and the helper reports
the minimum power-of-two IVSHMEM size needed.

Increase the IVSHMEM size in the VM configuration and restart the VM. The IDD
reads the new capacity when it starts; another helper reload is not normally
required. Allocating more shared memory than required does not improve
performance; it only reserves additional host RAM.

---

### Doc Idd Diagnostics (`doc/idd_diagnostics.rst`)

.. _idd_diagnostics:

IDD status and logs
###################

The IDD helper in the Windows notification area is the first place to check
when the virtual display is missing or slow. Its icon and tooltip report
whether the driver is using GPU acceleration or software processing.

Right-click the helper and open the log directory. The files are stored in:

``C:\ProgramData\Looking Glass (IDD)``

Collect these files when reporting an IDD fault:

* ``looking-glass-idd.txt``: display creation, GPU selection, modes,
  transport and frame scheduling;
* ``looking-glass-input.txt``: direct keyboard and mouse device activity;
* ``looking-glass-idd-service.txt``: service and driver control requests; and
* ``looking-glass-idd-helper.txt``: configuration, topology and user
  notifications.

Each log rotates through suffixes ``.1`` to ``.4``. Include the current file
and rotated files when the problem happened before the most recent restart.

Useful IDD lines
----------------

Render adapter
   Shows the Windows GPU selected by the IDD. A software-processing warning
   explains why HDR, cadence and high frame rates are unavailable.

IVSHMEM size
   Confirms which device was opened and its capacity. Compare this with the VM
   configuration and :ref:`libvirt_determining_memory`.

Filtered mode
   A configured mode was omitted because its frame buffers do not fit. Increase
   IVSHMEM or remove the oversized mode.

IddCx capabilities
   Shows whether the runtime HDR and wide-color-gamut interfaces are
   available. Their absence on Windows 10 is expected and does not prevent SDR
   use.

Frame schedule owner
   Reports the fastest active client's requested rate, guest acquisition rate
   and how many frames were published or skipped. Skipping excess guest frames
   is expected; it saves memory bandwidth while preserving the newest frame
   needed by the client.

Input owner
   Identifies the client currently allowed to send direct input. Only one
   client can own it at a time.

Client information
------------------

Run the client from a terminal and retain its complete output. Include:

* the client, IDD and OBS versions;
* Linux distribution and kernel;
* X11 or Wayland and the compositor name;
* host and guest GPU models and drivers;
* whether ``lgmp:allowDMA`` is enabled;
* the guest resolution and refresh rate; and
* exact steps that reproduce the fault.

Do not copy only the final error line. Startup output records the selected
transport, renderer, display server, audio backend and import method, which are
often needed to explain it.

---

### Doc Index (`doc/index.rst`)

Looking Glass |release| documentation
=====================================

Looking Glass is an open-source, low-latency way to use a Windows virtual
machine from Linux. The current setup uses a virtual display in the Windows
guest, shared memory for frames, and a native Linux client for display and
input.

.. toctree::
   :maxdepth: 2

   overview
   requirements
   quickstart

   build
   install

   usage
   troubleshooting
   obs
   faq

   legacy_host

.. toctree::
   :hidden:

   credits

More information:

* `Official Website <https://looking-glass.io/>`_
* `GitHub <https://github.com/gnif/LookingGlass>`_
* `Discord <https://discord.gg/52SMupxkvt>`_
* `Forum <https://level1techs.com/lg>`_
* `Community wiki <https://looking-glass.io/wiki/>`_
* IRC - #LookingGlass on `libera.chat <https://libera.chat/>`_

Donate:

* `GitHub <https://github.com/sponsors/gnif>`__
* `Ko-Fi <https://ko-fi.com/lookingglass>`_
* `Patreon <https://www.patreon.com/gnif>`_
* `PayPal <https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ESQ72XUPGKXRY>`_

Expand a cryptocurrency address to copy it:

.. raw:: html

   <details class="donation-address">
     <summary>Bitcoin (BTC)</summary>
     <code>14ZFcYjsKPiVreHqcaekvHGL846u3ZuT13</code>
   </details>
   <details class="donation-address">
     <summary>Ethereum (ETH)</summary>
     <code>0x6f8aEe454384122bF9ed28f025FBCe2Bce98db85</code>
   </details>
   <details class="donation-address">
     <summary>Monero (XMR)</summary>
     <code>47xM4zG7b2tEj4mnSywHve4ydZzn3wzhf22snDRB7aSEcXrgUBpoT2Z4phTnyFMi1sMyQtHbdufMYRQ2PzMn3PGUJAE1dpc</code>
   </details>

---

### Doc Input (`doc/input.rst`)

.. _client_input:

Keyboard and mouse input
########################

The current IDD provides keyboard and mouse input directly over LGMP. It uses
absolute positioning for normal desktop use and relative movement in capture
mode. SPICE remains available as a fallback when direct input is unavailable.

The client changes input provider automatically. If the displayed video has
fallen back to SPICE, the client also uses SPICE input so that the picture and
pointer always refer to the same guest.

Only one LGMP client controls direct input at a time. Starting another client
does not give both clients simultaneous control. Disconnecting or restarting
the IDD releases held keys and buttons before ownership changes.

Normal input
------------

Move the pointer into the guest view to use absolute desktop input. This keeps
the guest pointer aligned without requiring capture.

Direct IDD input supports the keyboard, media keys and up to 32 mouse buttons.
SPICE fallback uses relative mouse input and supports fewer extra buttons.

Capture mode
------------

Press the escape key, :kbd:`ScrLk` by default, to capture the mouse. Capture
mode confines the pointer and sends relative motion, which is appropriate for
games and applications that lock the cursor. Press the escape key again to
leave capture mode.

Common capture options are:

``input:captureOnFocus``
   Enter capture mode whenever the client receives focus.

``input:captureOnStart``
   Start captured.

``input:captureOnly``
   Disable guest input outside capture mode.

``input:rawMouse``
   Use raw relative mouse input in capture mode. This is usually best for
   games.

``input:mouseSens``
   Adjust relative sensitivity from -9 to 9. The default is 0.

``input:hideCursor``
   Hide the host cursor while Looking Glass renders the guest cursor.

Automatic keyboard capture
--------------------------

Set ``input:autoCapture=yes`` to grab the keyboard when the pointer enters the
guest view. Looking Glass predicts when the next mouse movement would leave
the guest area and releases the keyboard before that movement. This makes it
possible to move naturally between Looking Glass and the Linux desktop without
using the escape key for the keyboard.

Automatic keyboard capture is disabled by ``input:captureOnly=yes``. It also
keeps the keyboard grabbed while a mouse button is held so that dragging does
not unexpectedly leave the guest.

This is separate from full mouse capture: the pointer remains in normal
absolute mode. Use regular capture mode when an application requires relative
mouse input.

``input:grabKeyboardOnFocus`` instead keeps the keyboard grabbed while the
guest view is active. ``input:grabKeyboard`` controls whether full capture
mode grabs the keyboard.

SPICE fallback
--------------

Keep ``spice:input=yes`` when SPICE input fallback is wanted. It uses the VM's
default PS/2 keyboard and mouse, so no additional virtio input devices or
tablet are required.

To disable all SPICE input while keeping SPICE audio or clipboard services:

.. code-block:: ini

   [spice]
   input=no

If direct input is also unavailable, the client will display video without
being able to control the guest.

Evdev capture
-------------

Advanced users may list Linux evdev devices in ``input:evdev``. They become
active when Looking Glass captures their keyboard or relative-pointer role.
Automatic capture takes keyboard-only devices without taking mouse input from
the window system, while full capture takes both roles. Guest keyboard lock
LEDs are mirrored while a writable keyboard is captured. The client user must
be allowed to read the configured devices and write them for LED mirroring.
Keep ``input:evdevExclusive=yes`` unless input from other window-system
devices is also required.

---

### Doc Install (`doc/install.rst`)

.. _installing:

Installation
############

The Linux client must currently be built from source before it can be
installed. Follow the pages below in order for a new setup:

Configure the VM and shared memory, install the IDD in Windows, then install
the Linux client. The legacy Host page is an alternative for old workflows;
do not install both Windows servers.

.. toctree::

   install_libvirt
   install_idd
   install_client

---

### Doc Install Client (`doc/install_client.rst`)

.. _installing_client:

Client Application Installation
###############################

.. _client_install:

For Linux
---------

The Looking Glass Client receives frames from an implementation of the Looking
Glass Server on Windows and displays them on Linux. It also handles input,
audio, overlays and optional SPICE services.

There are currently no Linux distribution packages for the client. First
:ref:`build it from source <build_client_section>`, then run the following from
the client build directory as root::

   make install

To install for the current user only, configure the build with a user-local
prefix before installing::

   cmake -DCMAKE_INSTALL_PREFIX="$HOME/.local" ..
   make install

Ensure ``$HOME/.local/bin`` is in your ``PATH`` when using the user-local
installation.

---

### Doc Install Host (`doc/install_host.rst`)

.. _installing_host:
.. _host_install:

Legacy Host Application installation
####################################

.. warning::

   The Host Application is the legacy implementation of the Looking Glass
   Server. New installations should use the :doc:`Looking Glass IDD
   <install_idd>`.

   B7 is the last recommended release when non-capture mouse input through the
   Host Application is required. Use the matching B7 client and documentation
   for that workflow. Do not combine a B7 Host with current components.

The legacy Looking Glass Host Application captures frames from the guest using a
capture API, and sends them to the
:ref:`client <client_install>`β€”be it on the host OS (hypervisor) or another
Virtual Machineβ€”through a low-latency transfer protocol over shared memory.

You can get the host program in two ways:

-  Download a matching legacy binary from https://looking-glass.io/downloads

-  Download the source code as described in :ref:`building`, then
   :ref:`build the host <host_building>`.

.. _host_install_linux:

For Linux
^^^^^^^^^

While the host application can be compiled and is somewhat functional for Linux
it is currently considered incomplete and not ready for usage. As such use at
your own risk and do not ask for support.

.. _host_install_osx:


For OSX
^^^^^^^

Currently there is no support or plans for support for OSX due to technical
limitations.

.. _host_install_windows:

For Windows
^^^^^^^^^^^

To begin, you must first run the Windows VM with the changes noted in the
:doc:`install_libvirt` section.

.. _installing_the_ivshmem_driver:

Installing the IVSHMEM driver
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since B6 the host installer available on the official Looking Glass website
comes with the IVSHMEM driver and will install this for you. If you are running
an older version of Looking Glass please refer to the documentation for your
version.

.. _host_install_service:

Installing the Looking Glass service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After installing your IVSHMEM driver, we can now install the Looking Glass Host
onto our Windows Virtual Machine.

1. First, run ``looking-glass-host-setup.exe`` as an administrator
   (:ref:`Why? <faq_host_admin_privs>`)
2. You will be greeted by an intro screen. Press ``Next`` to continue.
3. You are presented with the |license| license. Please read and agree to the
   license by pressing ``Agree``.
4. You can change the install path if you wish, otherwise press ``Next`` to
   continue.
5. You may enable or disable options on this screen to configure the
   installation. The default values are recommended for most users.
   Press ``Install`` to begin installation.
6. After a few moments, installation will complete, and you will have a
   running instance of Looking Glass. If you experience failures, you can
   see them in the install log appearing in the middle of the window.
7. Press ``Close`` to exit the installer.

Command line users can run ``looking-glass-host-setup.exe /S`` to execute a
silent install with default options selected. Further configuration from the
command line can be done with flags. You can list all available flags by
running ``looking-glass-host-setup.exe /?``.

Legacy configuration
~~~~~~~~~~~~~~~~~~~~

.. toctree::
   :maxdepth: 1

   host_usage
   build_host

---

### Doc Install Idd (`doc/install_idd.rst`)

.. _installing_idd:

Looking Glass IDD
#################

.. _install_idd:

The Looking Glass IDD is the recommended Looking Glass server implementation for
Windows guests. Download the ``looking-glass-idd-setup.exe`` installer that
matches the client release, run it as an administrator inside the Windows guest
and follow the installer.

The installer includes the display driver, direct input driver and IDD helper.
It can also install the IVSHMEM driver. If the legacy Host service is present,
allow the installer to disable it so that only one Looking Glass server is
active.

The display may briefly disappear while Windows installs or reloads the
driver. Restart Windows if the installer requests it.

Install
-------

1. Download the IDD installer from the same release as the client source.
2. Run ``looking-glass-idd-setup.exe`` as an administrator in Windows.
3. Select **IVSHMEM Driver** if a suitable IVSHMEM driver is not already
   installed in the guest.
4. Leave **Indirect Display Driver (IDD)** selected.
5. If offered, leave **Disable old host app** selected. Running two servers
   against the same shared-memory device is not supported.
6. Complete the installation and restart Windows if requested.

After installation, Windows should show a display named Looking Glass and the
IDD helper should appear in the notification area. The helper icon reports
whether the IDD is using GPU acceleration or software processing.

The IDD installer also installs its direct input driver. There is no separate
input package to install.

Upgrade
-------

Close active clients and OBS sources, then run the new matching IDD installer
over the existing installation. Upgrade the Linux client and OBS plugin to the
same release before using them again.

Windows may briefly remove and recreate the virtual display. Restart Windows
when the installer reports that a restart is required.

Uninstall
---------

Remove **Looking Glass (IDD)** from Windows **Installed apps** or **Programs
and Features**. This removes both the display and input drivers and deletes
custom IDD modes and preferences. The optional IVSHMEM files are removed from
the Looking Glass installation directory, but an IVSHMEM driver package that
was already installed in Windows is not uninstalled.

If you are returning to the legacy Host Application, re-enable or reinstall
its service only after the IDD has been removed.

Silent installation
-------------------

The installer accepts these options for managed installations:

``/S``
   Install silently. The uppercase spelling is required.

``/ivshmem``
   Install the bundled IVSHMEM driver when it is present in the installer.

``/D=path``
   Change the installation directory. This must be the final option and must
   not be quoted.

Configuration and diagnostics
-----------------------------

.. toctree::
   :maxdepth: 1

   idd_configuration

For faults, the helper can open the IDD log directory directly. See
:ref:`idd_diagnostics` for the files to collect.

---

### Doc Install Libvirt (`doc/install_libvirt.rst`)

.. _installing_libvirt:

libvirt/QEMU Installation
#########################

This article assumes you already have a working `libvirt` Windows virtual
machine. If you use `virt-manager`, this guide also applies because
`virt-manager` uses `libvirt` as its back end. A passed-through or virtual GPU
is strongly recommended, but the IDD can start in software mode without one.

.. _libvirt_determining_memory:

Determining memory
^^^^^^^^^^^^^^^^^^

Calculate the IVSHMEM requirement as:

.. math::

  \text{REQUIRED BYTES} =
  \left(\left\lceil\frac{\text{WIDTH} \times 4}{256}\right\rceil
  \times 256\right) \times \text{HEIGHT} \times 3
  + (4 \times 1024 \times 1024)

Convert the result to MiB and round it up to the next power of two. The common
values below have already been rounded.

If a configured mode does not fit, the IDD omits it from the Windows mode list.
If a client-requested dynamic resolution does not fit, the helper refuses it
and reports the minimum power-of-two size to configure. The current IDD does
not publish a truncated frame.

.. note::
   Increasing this value beyond what you need does not improve performance. It
   only reserves more host RAM for the VM.

.. list-table:: Common IDD values
   :widths: 60 40
   :header-rows: 1

   * - Maximum resolution
     - Total IVSHMEM size (MiB)
   * - 1920x1080 (1080p)
     - 32
   * - 1920x1200
     - 32
   * - 2560x1440 (1440p)
     - 64
   * - 3440x1440
     - 64
   * - 3840x2160 (4K)
     - 128
   * - 5120x1440
     - 128
   * - 5120x2880 (5K)
     - 256
   * - 7680x4320 (8K)
     - 512

.. _libvirt_determining_memory_hdr:

HDR uses the same 32-bit IDD transport allocation as SDR, so it does not double
the IVSHMEM requirement. Native Linux HDR presentation has separate compositor
and display requirements; see :ref:`client_hdr`.

.. _libvirt_ivshmem:

IVSHMEM
^^^^^^^

There are two methods of configuring IVSHMEM, using shared memory directly, or
using the KVMFR kernel module. While the KVMFR module is slightly more
complicated to configure, it substantially improves performance as it allows
Looking Glass to use your GPUs DMA engine to transfer the frame data.

.. toctree::
   :maxdepth: 1

   ivshmem_kvmfr
   ivshmem_shm

.. seealso::

   :ref:`igpu_kvmfr_recommended`


.. _libvirt_spice_server:

Keyboard/mouse/display/audio
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The IDD provides the primary video, keyboard and mouse paths directly over
LGMP. SPICE is optional, but is recommended for display fallback, clipboard
and audio services.

.. note::
  The current client owns its SPICE connection and service settings. The
  canonical options are ``spice:enable``, ``spice:input``,
  ``spice:clipboard``, ``spice:audio`` and ``spice:usbAudio``.

Keep a ``<graphics type='spice'>`` device if you want these services. For a
usable display fallback, set the VM's ``<video>`` model to ``vga``.

The direct IDD input path supports absolute desktop positioning, relative
capture-mode input, keyboards, media keys and extended mouse buttons. SPICE
fallback uses the VM's default PS/2 keyboard and mouse. Looking Glass does not
require additional virtio keyboard, mouse or tablet devices for either path.

For classic SPICE audio, add a standard Intel HDA audio device:

.. code:: xml

  <sound model='ich9'>
    <audio id='1'/>
  </sound>
  <audio id='1' type='spice'/>

The recommended emulated USB audio path does not need this HDA device. It
requires a SPICE USB channel and is covered in :ref:`client_usb_audio`. For
clipboard synchronization, continue with
:ref:`libvirt_clipboard_synchronization`.

.. _libvirt_clipboard_synchronization:

Clipboard synchronization
^^^^^^^^^^^^^^^^^^^^^^^^^

Looking Glass can synchronize the clipboard between the host and guest using
the SPICE guest agent.

1. Install the SPICE guest tools from
https://www.spice-space.org/download.html#windows-binaries.

2. Configure your VM to enable the SPICE guest agent:

-  QEMU

.. code:: bash

   -device virtio-serial-pci \
   -chardev spicevmc,id=vdagent,name=vdagent \
   -device virtserialport,chardev=vdagent,name=com.redhat.spice.0

-  libvirt

.. code:: xml

     <channel type="spicevmc">
       <target type="virtio" name="com.redhat.spice.0"/>
       <address type="virtio-serial" controller="0" bus="0" port="1"/>
     </channel>
     

.. _libvirt_apparmor:

AppArmor
^^^^^^^^

For libvirt versions before **5.10.0**, if you are using AppArmor, you
need to add permissions for QEMU to access the shared memory file. This
can be done by adding the following to
``/etc/apparmor.d/local/abstractions/libvirt-qemu``::

   /dev/shm/looking-glass rw,

then, restart AppArmor.

.. code:: bash

   sudo systemctl restart apparmor

.. _libvirt_memballoon_tweak:

Memballoon
^^^^^^^^^^

The VirtIO memballoon device enables the host to dynamically reclaim memory
from your VM by growing the balloon inside the guest, reserving reclaimed
memory. Libvirt adds this device to guests by default.

However, this device causes major performance issues with VFIO passthrough
setups, and should be disabled.

Find the ``<memballoon>`` tag and set its type to ``none``:

.. code:: xml

   <memballoon model="none"/>

.. _libvirt_additional_tuning:

Additional tuning
^^^^^^^^^^^^^^^^^

Looking Glass is latency sensitive and as such it may suffer microstutters if
you have not properly tuned your virtual machine. The physical display output
of your GPU will usually not show such issues due to the nature of the hardware
but be sure that if you are experiencing issues the following tuning is
required to obtain optimal performance.

1. Do not assign all your CPU cores to your guest VM, you must at minimum
   reserve two CPU cores (4 threads) for your host system to use. For example,
   if you have a 6 core CPU, only assign 4 cores (8 threads) to the guest.

2. Ensure you correctly pin your VMs vCPU threads to the correct cores for your
   CPU architecture.

3. If you are on a NUMA architecture (dual CPU, or early Threadripper) be sure
   that you pin the vCPU threads to the physical CPU/die attached to your GPU.

4. Just because your GPU is in a slot that is physically x16 in size, does not
   mean your GPU is running at x16, this is dependent on how your motherboard
   is physically wired and the physical slot may be limited to x4 or x8.

5. Be sure to set your CPU model type to `host-passthrough` so that your guest
   operating system is aware of the acceleration features of your CPU and can
   make full use of them.

6. AMD users be sure that you have the CPU feature flag `topoext` enabled or
   your guest operating system will not be aware of which CPU cores are
   hyper-thread pairs.

How to perform these changes is left as an exercise to the reader.

---

### Doc Ivshmem Kvmfr (`doc/ivshmem_kvmfr.rst`)

:orphan:
.. _ivshmem_kvmfr:

IVSHMEM with the KVMFR module (Recommended)
###########################################

The kernel module exposes IVSHMEM to Looking Glass and can export its frame
buffers for direct GPU import.

.. _ivshmem_kvmfr_prereq:

Prerequisites
-------------

The Linux kernel headers for your kernel version are required for building
along with `dkms` to manage the module when you upgrade your kernel.

.. code:: bash

   apt-get install linux-headers-$(uname -r) dkms

Then switch to the ``module/`` directory

.. code:: bash

   cd module/

.. _ivshmem_kvmfr_dkms:

Installing
~~~~~~~~~~

To install the module into DKMS, run

.. code:: bash

   dkms install "."

.. _ivshmem_kvmfr_loading:

Loading
~~~~~~~

Using the value you should have already calculated as per
:ref:`Determining Memory <libvirt_determining_memory>`, simply use
``modprobe`` with the parameter ``static_size_mb``, for example:

.. code:: bash

   modprobe kvmfr static_size_mb=64

Alternatively you can make this setting permanent by creating the file
``/etc/modprobe.d/kvmfr.conf`` with the following content.

.. code:: text

   options kvmfr static_size_mb=64

After this has been done, simply running ``modprobe kvmfr`` is all that is
required.

.. note::

   Don't forget to adjust ``static_size_mb`` to your needs.

.. _ivshmem_kvmfr_systemd:

systemd-modules-load
~~~~~~~~~~~~~~~~~~~~

For convenience, you may load the KVMFR module when starting your computer.
We can use the ``systemd-modules-load.service(8)`` service for this task.

Create the file ``/etc/modules-load.d/kvmfr.conf`` with the following
contents::

   # KVMFR Looking Glass module
   kvmfr

This will now run the next time you start your machine.

.. _ivshmem_kvmfr_verification:

Verification
~~~~~~~~~~~~

If everything has been done correctly you should see the following output in
dmesg:

.. code:: text

   kvmfr: creating 1 static devices

You should now also have the character device ``/dev/kvmfr0``

.. code:: bash

   $ ls -l /dev/kvmfr0
   crw------- 1 root root 242, 0 Mar  5 05:53 /dev/kvmfr0

.. warning::

   If you start the VM prior to loading the module, QEMU will create the file
   ``/dev/kvmfr0`` as a regular file. You can confirm if this has happened by
   running ``ls -l /dev/kvmfr0`` and checking if the file size is greater than
   zero, or the permissions do not start with ``c``. If this has occurred, you
   must stop the VM before deleting the regular file. Load the KVMFR module,
   confirm that it recreated ``/dev/kvmfr0`` as a character device whose
   permissions start with ``c``, then start the VM again.

.. _ivhsmem_kvmfr_permissions:

Permissions
~~~~~~~~~~~

The module will create the ``/dev/kvmfr0`` node, which represents the KVMFR
interface. To use the interface, you need permission to access it by either
creating a udev rule to ensure your user can read and write to it, or simply
change its ownership manually, i.e.:

.. code:: bash

   sudo chown user:kvm /dev/kvmfr0

(replace ``user`` with your username)

As an example, you can create a new file in ``/etc/udev/rules.d/70-kvmfr.rules``
with the following contents::

   SUBSYSTEM=="kvmfr", GROUP="kvm", MODE="0660", TAG+="uaccess"

.. note::

   Make sure the udev rule file name ordinal value is below (lexically sorts before) ``73-seat-late.rules``
   to allow the uaccess tag to be processed properly.

.. _ivshmem_kvmfr_libvirt:

libvirt
~~~~~~~

Using the module in libvirt requires adding a ``<qemu:commandline>`` block to
your libvirt XML configuration. That block, in turn, requires modifying the
XML domain namespace. To modify the namespace edit the ``<domain>`` tag at
the top of your XML config to:

.. code:: xml

   <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>

then add one of the ``<qemu:commandline>`` blocks below based on your
QEMU/libvirt versions.

.. note::

   Make sure to add both the block and the domain namespace change in a
   single editing session prior to saving it. Failure to do so will cause
   libvirt to reject the changes.

Starting with QEMU 6.2 and libvirt 7.9, JSON style QEMU configuration is the
default syntax. Users running QEMU 6.2 or later **and** libvirt 7.9 or later,
should use this XML block to configure their VM for kvmfr:

.. code:: xml

   <qemu:commandline>
     <qemu:arg value="-device"/>
     <qemu:arg value="{'driver':'ivshmem-plain','id':'shmem0','memdev':'looking-glass'}"/>
     <qemu:arg value="-object"/>
     <qemu:arg value="{'qom-type':'memory-backend-file','id':'looking-glass','mem-path':'/dev/kvmfr0','size':67108864,'share':true}"/>
   </qemu:commandline>

.. note::

   -  The ``'size'`` tag represents the size of the shared memory device in
      bytes. Once you determine the proper size of the device as per
      :ref:`Determining Memory <libvirt_determining_memory>`, use the figure you
      got to calculate the size in bytes:

     ``size_in_MB x 1024 x 1024 = size_in_bytes``

If you are running QEMU older than 6.2 or libvirt older than 7.9, please use
legacy syntax for IVSHMEM setup:

.. code:: xml

   <qemu:commandline>
     <qemu:arg value="-device"/>
     <qemu:arg value="ivshmem-plain,id=shmem0,memdev=looking-glass"/>
     <qemu:arg value="-object"/>
     <qemu:arg value="memory-backend-file,id=looking-glass,mem-path=/dev/kvmfr0,size=64M,share=yes"/>
   </qemu:commandline>

.. note::

   Using the legacy syntax on QEMU 6.2/libvirt 7.9 may cause QEMU to
   abort with the following error message:
   "``error: internal error: ... PCI: slot 1 function 0 not available for pcie-root-port, in use by ivshmem-plain``"

Running libvirt this way violates AppArmor and cgroups policies, which will
block the VM from running. These policies must be amended to allow the VM
to start.

.. tip::

   If you are not sure, you likely have cgroups also as this is usually deployed
   and configured by default by most distributions when you install libvirt.

AppArmor
^^^^^^^^

Create ``/etc/apparmor.d/local/abstractions/libvirt-qemu`` if it doesn't exist
and add the following:

.. code:: text

   # Looking Glass
   /dev/kvmfr0 rw,

cgroups
^^^^^^^

Edit the file ``/etc/libvirt/qemu.conf`` and uncomment the
``cgroup_device_acl`` block, adding ``/dev/kvmfr0`` to the list. Restart
``libvirtd`` to apply it:

.. code:: bash

   sudo systemctl restart libvirtd.service

.. _ivshmem_kvmfr_qemu:

QEMU
~~~~

If you are using QEMU directly without libvirt, add the following arguments to your
``qemu`` command line::

   -device ivshmem-plain,id=shmem0,memdev=looking-glass
   -object memory-backend-file,id=looking-glass,mem-path=/dev/kvmfr0,size=64M,share=yes

.. note::

   The ``size`` argument must be the same size you passed
   to the ``static_size_mb`` argument when loading the kernel module.

---

### Doc Ivshmem Shm (`doc/ivshmem_shm.rst`)

:orphan:
.. _ivshmem_shm:

IVSHMEM with standard shared memory
###################################

Use this method only when the KVMFR kernel module is unavailable. A standard
shared-memory file cannot provide KVMFR's DMA-BUF export, so the client must
copy the frame before uploading it to the host GPU.

Add the following to your libvirt machine configuration inside the
'devices' section by running ``virsh edit <VM>`` where ``<VM>`` is the name of
your virtual machine.

.. code:: xml

   <shmem name='looking-glass'>
     <model type='ivshmem-plain'/>
     <size unit='M'>64</size>
   </shmem>

.. note::
  If you are using QEMU directly without libvirt the following arguments are
  required instead.

  Add the following to the commands to your QEMU command line, adjusting
  the ``bus`` parameter to suit your particular configuration:

  .. code:: bash

     -device ivshmem-plain,memdev=ivshmem,bus=pcie.0 \
     -object memory-backend-file,id=ivshmem,share=on,mem-path=/dev/shm/looking-glass,size=64M

The example uses 64 MiB. Replace it with the value from
:ref:`Determining memory <libvirt_determining_memory>` when using a larger
resolution.

.. warning::
   Stop the VM before changing this size. You may need to remove the existing
   ``/dev/shm/looking-glass`` file so QEMU can recreate it at the new size.
   Check its permissions afterward; see :ref:`libvirt_shmfile_permissions`.

.. _libvirt_shmfile_permissions:

Permissions
~~~~~~~~~~~

The shared memory file used by IVSHMEM is found in ``/dev/shm/looking-glass``.
By default, it is owned by QEMU, and does not give read/write permissions to
your user, which are required for Looking Glass to run properly.

You can use ``systemd-tmpfiles`` to create the file before running your VM,
granting the necessary permissions which allow Looking Glass to use the file
properly.

Create a new file ``/etc/tmpfiles.d/10-looking-glass.conf``, and populate it
with the following::

   # Type Path               Mode UID  GID Age Argument

   f /dev/shm/looking-glass 0660 user kvm -

Change ``UID`` to the user name you will run Looking Glass with, usually your
own.

---

### Doc Legacy Host (`doc/legacy_host.rst`)

.. _legacy_host:

Legacy Host Application
#######################

.. warning::

   The Host Application is a legacy server application. New installations should
   use the prebuilt :doc:`Looking Glass IDD `. These build
   instructions are retained for the complete matching B7 stack described in
   :ref:`legacy_host_policy`.

.. note::

   `Host` in this context refers to the `Looking Glass (LG) host server application`,
   to which the LG client connects to, it thus does not refer to the `host OS`!

   A common setup is to have a `host OS` running a `guest VM`. In such a setup
   the `client application` runs on the `host OS`; and the `host application`
   on the `guest VM`.

   The term `Host application` was chosen over `Guest application`, because LG
   can be run in a VM to VM configuration, in which case both Host Application and
   Client Application are run inside VM Guests.

The Windows Host Application is no longer the recommended server implementation.
It is missing many of the features available in the Looking Glass IDD, such as:

* No additional video capture overhead;
* Usage without a monitor or dummy plug connected;
* Automatically resizing the guest to fit the client application viewport;
* HDR support; or
* Usage in virtual machines without GPU acceleration.

B7 is the last recommended version of the legacy host application for users who
require its non-capture mouse input workflow. Use the complete matching B7 stack
for that workflow rather than mixing B7 and current components.

The documentation is included here for completeness.


.. toctree::
   :maxdepth: 1

   Installation 
   Configuration <host_usage>
   Building from source 

---

### Doc Obs (`doc/obs.rst`)

.. _obs_plugin:
.. _open_broadcaster_software:

OBS plugin
##########

The Looking Glass OBS plugin reads video from LGMP directly instead of
capturing the client window. The client can stay hidden or show overlays
without adding them to the OBS source. This source does not provide audio or
input; add the required audio source separately in OBS.

Use an OBS plugin from the same Looking Glass release as the IDD and client.
The shared-memory protocol is versioned and mismatched components will not
connect.

.. _obs_building:

Build and install
-----------------

On Debian-based systems, install the OBS headers and the small set of build
dependencies used by the plugin:

.. code:: bash

   apt-get install cmake gcc libobs-dev libdw-dev libunwind-dev make pkg-config

Use ``-DENABLE_BACKTRACE=no`` when configuring if ``libdw-dev`` and
``libunwind-dev`` are intentionally omitted.

From the Looking Glass source directory, build the plugin for the current
user:

.. code:: bash

   mkdir -p obs/build
   cd obs/build
   cmake -DUSER_INSTALL=1 ../
   make
   make install

For a system-wide installation, omit ``-DUSER_INSTALL=1`` and run
``sudo make install``.

Add the source
--------------

1. Start OBS after installing the plugin.
2. In **Sources**, select **Add** and then **Looking Glass Client**.
3. Set **SHM File** to the same KVMFR device or shared-memory file used by the
   VM.
4. Enable **Hide mouse cursor** if OBS should omit the guest pointer.
5. Leave **Use DMABUF import** enabled with KVMFR unless the OBS log reports
   that the host graphics driver cannot import it.

The OBS process needs read and write access to ``/dev/kvmfr0``. Use the same
udev rule as the Looking Glass client; see :ref:`ivhsmem_kvmfr_permissions`.

.. figure:: images/Looking-Glass-OBS-Source-Add.png
   :alt: Adding a Looking Glass source in OBS

   Adding the Looking Glass source

DMA-BUF and CPU copy
--------------------

DMA-BUF import is available with OBS 27 or newer and is enabled by default.
It imports KVMFR into the GPU and makes a full-frame GPU snapshot into
OBS-owned storage before releasing the shared frame. It avoids the CPU upload,
but it is not a zero-copy path to the final OBS texture. If import or the
snapshot fails, the plugin falls back to a CPU copy and records the failure in
the OBS log. A plain POSIX shared-memory file always uses the CPU path.

Disabling DMA-BUF is useful for diagnosis, but it increases CPU and memory
bandwidth use at high resolutions.

HDR
---

HDR-aware OBS color-space support requires OBS 28 or newer. The plugin reports
the source color space from the IDD frame, but OBS must also be configured with
an HDR canvas and a suitable recording or streaming output. An SDR OBS project
will not become HDR merely because the guest frame is HDR.

Frame rate and multiple clients
-------------------------------

An active OBS source requests the global frame rate configured under **OBS
Settings > Video**. There is no separate FPS control in the Looking Glass
source. The IDD uses the fastest request among all active consumers, so a 120
Hz client can raise the server cadence while OBS records at 60 FPS. Each
consumer still selects the newest frame for its own deadline.

The OBS source releases its cadence request while it is inactive or hidden.
IDD log lines that report acquired, skipped and published frames are expected:
frames newer than the previous publication may be acquired and superseded
without copying all of them through IVSHMEM.

Troubleshooting
---------------

No source image
   Check KVMFR permissions, the selected device and component versions. The
   OBS log reports both expected protocol versions when they do not match.

High CPU use
   Confirm that DMA-BUF stayed enabled and that import succeeded. Also check
   whether OBS and the client are both performing expensive scaling.

Jitter when another client starts
   Confirm OBS is using a current matching plugin. Current cadence support
   allows consumers with different refresh rates without forcing OBS to
   display every frame requested by the fastest client.

HDR looks washed out
   Check the OBS canvas color space, output format and the guest HDR state. Do
   not apply the client's HDR-to-SDR settings to the independent OBS source.

OBS is available from https://obsproject.com/ and is packaged by most Linux
distributions as ``obs-studio`` or ``obs``.

---

### Doc Options (`doc/options.rst`)

.. _client_options:
.. _client_cli_options:
.. _client_full_command_options:

Client option reference
#######################

The exact option set depends on how the client was built. Use this command for
the complete reference, including defaults and short forms:

.. code:: bash

   looking-glass-client --help

Use only the canonical names shown by that command. Older configuration names
may remain as compatibility aliases, but they print a warning and can be
removed in a later release.

Syntax
------

Long options use ``section:name=value``:

.. code:: bash

   looking-glass-client win:fullScreen=yes lgmp:allowDMA=no

Short options may take a separate argument:

.. code:: bash

   looking-glass-client -F -f /dev/kvmfr1

Configuration files use the section as an INI heading:

.. code-block:: ini

   [win]
   fullScreen=yes

   [lgmp]
   allowDMA=no

Common options
--------------

.. list-table:: Application and transport
   :widths: 34 16 50
   :header-rows: 1

   * - Option
     - Default
     - Purpose
   * - ``app:transport``
     - ``lgmp``
     - Select the primary transport, normally ``lgmp`` or ``spice``
   * - ``lgmp:shmDevice``
     - automatic
     - Select the KVMFR device or shared-memory file
   * - ``lgmp:allowDMA``
     - ``yes``
     - Permit direct GPU imports when supported
   * - ``spice:enable``
     - ``yes``
     - Enable the built-in SPICE transport and fallback services
   * - ``spice:host``
     - ``127.0.0.1``
     - Set the SPICE server address or Unix socket
   * - ``spice:port``
     - ``5900``
     - Set the SPICE port; 0 selects a Unix socket
   * - ``spice:input``
     - ``yes``
     - Permit SPICE input fallback
   * - ``spice:clipboard``
     - ``yes``
     - Permit SPICE clipboard service
   * - ``spice:audio``
     - ``yes``
     - Permit SPICE audio service
   * - ``spice:usbAudio``
     - ``yes``
     - Use the recommended emulated USB audio device instead of classic SPICE
       audio

.. list-table:: Window and display
   :widths: 34 16 50
   :header-rows: 1

   * - Option
     - Default
     - Purpose
   * - ``win:size``
     - ``1024x768``
     - Set the initial client window size
   * - ``win:fullScreen``
     - ``no``
     - Start full screen
   * - ``win:autoResize``
     - ``no``
     - Follow guest resolution changes
   * - ``win:setGuestRes``
     - ``yes``
     - Ask a supporting server to follow the client viewport
   * - ``win:fpsMin``
     - automatic
     - Set the minimum redraw rate; 0 disables it and is not recommended
   * - ``win:jitRender``
     - ``no``
     - Render close to the predicted presentation deadline
   * - ``win:showFPS``
     - ``no``
     - Show the FPS and UPS widget
   * - ``egl:mapHDRtoSDR``
     - ``yes``
     - Tone-map HDR frames for an SDR output
   * - ``egl:preset``
     - none
     - Load a named filter preset at startup

.. list-table:: Input
   :widths: 34 16 50
   :header-rows: 1

   * - Option
     - Default
     - Purpose
   * - ``input:escapeKey``
     - ``KEY_SCROLLLOCK``
     - Set the capture/menu key; use ``help`` to list accepted names
   * - ``input:autoCapture``
     - ``no``
     - Grab the keyboard inside the guest view and release it before exit
   * - ``input:captureOnly``
     - ``no``
     - Enable guest input only while captured
   * - ``input:grabKeyboard``
     - ``yes``
     - Grab the keyboard in capture mode
   * - ``input:rawMouse``
     - ``no``
     - Use raw relative movement in capture mode
   * - ``input:mouseRedraw``
     - ``yes``
     - Repaint at display cadence when only the cursor changes

.. list-table:: Audio and clipboard
   :widths: 34 16 50
   :header-rows: 1

   * - Option
     - Default
     - Purpose
   * - ``clipboard:toVM``
     - ``yes``
     - Allow clipboard transfers to the guest
   * - ``clipboard:toLocal``
     - ``yes``
     - Allow clipboard transfers from the guest
   * - ``audio:periodSize``
     - ``512``
     - Request an audio backend period in samples
   * - ``audio:latencyOffset``
     - ``6``
     - Add safety margin to the classic SPICE audio buffer in milliseconds
   * - ``audio:resampler``
     - ``auto``
     - Select classic SPICE resampling with ``auto``, ``libsamplerate`` or the
       backend
   * - ``audio:micDefault``
     - ``prompt``
     - Select ``prompt``, ``allow`` or ``deny`` for microphone requests
   * - ``audio:debug``
     - ``no``
     - Log detailed audio synchronization statistics

Advanced options
----------------

Polling intervals, renderer damage handling, display-server protocol choices
and audio-device selectors are intentionally omitted here. They are useful for
diagnosis but can make latency or reliability worse when changed without a
specific reason. Consult ``--help`` and record the original value before
experimenting.

---

### Doc Overview (`doc/overview.rst`)

.. _overview:

Overview
########

Looking Glass displays a Windows virtual machine in a low-latency Linux
window. It transfers completed frames through shared memory instead of sending
compressed video over a network. The current IDD provides video and direct
input through LGMP, while SPICE normally provides audio, clipboard and fallback
services.

The names used throughout this guide are:

Linux host
   The physical machine running KVM/QEMU and the Looking Glass Client.

Windows guest
   The Windows virtual machine shown by Looking Glass.

Looking Glass Client
   The Linux application that displays the guest and sends user input. There
   are currently no distribution packages for it, so it must be built from
   source before installation.

Looking Glass Server
   The Windows guest application that generates the video feed for the Looking
   Glass client. There are broadly two implementations of the server: the
   Looking Glass IDD and the legacy host application.

Looking Glass IDD
   The recommended Windows Indirect Display Driver. It creates a virtual
   monitor, sends its frames to the client and provides direct keyboard and
   mouse input. The installer also includes the IDD helper and input driver.

Legacy Host Application
   The older Windows capture application. It captures an existing display
   rather than creating a virtual one. It is documented for existing B7
   workflows, but is no longer recommended for current installations.

KVMFR and IVSHMEM
   The shared-memory path between the Windows guest and Linux host. KVMFR is
   the recommended Linux kernel module because it permits direct GPU imports
   where supported.

LGMP
   The protocol used by Looking Glass components over shared memory.

SPICE
   An optional fallback transport for video, input, audio and clipboard
   services. With the IDD active, Looking Glass normally uses its direct input
   path and uses SPICE only for services that are enabled and available.

Recommended setup
-----------------

For a new installation, use:

* the current Looking Glass Client on the Linux host;
* KVMFR shared memory attached to the Windows guest;
* the matching Looking Glass IDD in the Windows guest; and
* SPICE only for the fallback or convenience services you need.

Use matching Looking Glass releases for the current client, IDD, and OBS plugin.
The shared-memory protocol changes between releases and incompatible components
will not connect. Users of the legacy host application must use the complete
matching B7 stack described below.

.. _legacy_host_policy:

Legacy Host Application
-----------------------

The Host Application is the legacy implementation of the Looking Glass server.
The IDD is recommended because it does not require a physical monitor or dummy
plug and supports current display, input and scheduling features.

If your workflow specifically requires non-capture mouse input with the Host
Application, B7 is the last recommended release. Use the matching B7 client,
Host Application and B7 documentation together; do not mix B7 components with
current releases.

Download the complete B7 release from https://looking-glass.io/downloads and see
the :ref:`legacy_host` section.

---

### Doc Performance (`doc/performance.rst`)

.. _client_performance:

Measure performance and latency
###############################

Press :kbd:`ScrLk` + :kbd:`D` for the compact FPS and UPS display. Press
:kbd:`ScrLk` + :kbd:`T` for the timing graphs.

FPS and UPS
-----------

FPS
   How often the client completed a render and swap. Cursor-only and overlay
   redraws can raise this without a new desktop frame.

UPS
   How often this client consumed a new guest frame. It can be lower than the
   guest render rate because cadence deliberately skips frames that were
   superseded before the client's next deadline.

A higher number is not automatically lower latency. Use the stage graph to
find where time is spent and confirm that the displayed rate meets the output
you are actually using.

Frame latency graphs
--------------------

The **Minimum**, **Maximum** and **Average** panels show a running history in
200 ms buckets. Each colored band is a sequential stage. The thickness of a
band is its duration; its height above zero includes all earlier bands. The top
of the final **Swap** band is the plotted total through return from EGL swap.

The current incomplete bucket is not plotted. This keeps the newest point from
jumping as samples arrive. Each panel also keeps a stable vertical scale with
hysteresis, so read the millisecond axis when comparing panels.

.. list-table:: Capture and transport stages
   :widths: 18 82
   :header-rows: 1

   * - Band
     - What it measures
   * - **Capture**
     - Time spent successfully acquiring the next IDD swap-chain buffer. This
       is not Windows Graphics Capture and does not include guest application
       rendering or the wait between unsuccessful acquisition attempts.
   * - **Post**
     - IDD preparation before the measured copy, including format and damage
       processing, synchronization and any required compute effect.
   * - **Copy**
     - IDD work that copies the selected frame into retained or transport
       storage. It may include more than one copy when the selected path needs
       it.
   * - **Ready**
     - Remaining IDD queue, fence, finalization and publication overhead not
       included in Post, Copy or Hold.
   * - **Hold**
     - Time a prepared hardware frame waits for the cadence deadline before
       its final transport copy starts. This is intentional scheduling time.
       Software processing does not use cadence and reports zero.
   * - **Transport**
     - Inferred publication-to-client delay for a frame matched to a cadence
       deadline. It is not an β€œIVSHMEM copy” measurement and is omitted when
       server and client timing cannot be matched safely.

.. list-table:: Client EGL stages
   :widths: 18 82
   :header-rows: 1

   * - Band
     - What it measures
   * - **Import**
     - Work needed to make the frame usable by EGL, such as a CPU staging copy
       or DMA import and snapshot submission.
   * - **Dispatch**
     - Remaining frame-thread validation, format, damage and queueing work
       after Import.
   * - **Queue**
     - Time from queueing the accepted update until the render thread begins.
       This includes waiting for display cadence and deliberate JIT slack.
   * - **Prepare**
     - Client render-thread preparation such as commands, resize handling,
       geometry and invalidation decisions.
   * - **Setup**
     - EGL state, damage history, HDR and pointer setup before desktop drawing.
   * - **Effects**
     - Evaluation of the active EGL filter chain.
   * - **Desktop**
     - Completion of the frame texture and drawing the guest desktop, with
       Effects shown separately.
   * - **Compose**
     - Cursor, letterbox, damage diagnostics and HDR composition around the
       desktop. The interactive UI overlay is deliberately excluded.
   * - **Swap**
     - Time inside the display-server EGL swap call. It may include blocking
       in EGL or compositor submission, but not later physical scanout.

Only guest frames actually consumed by EGL contribute server samples.
Superseded frames are not treated as latency samples. The minimum and maximum
for each band are calculated independently, so the top of a minimum or maximum
stack can combine stages from different frames. Use those panels to locate
stage spikes, not as the measured total of one specific frame.

Cadence and Hold
----------------

The Linux display and Windows guest have independent clocks. Looking Glass
does not subtract their raw timestamps. The server reports durations, while
periods, generations and deadlines identify a matching cadence event. The
Transport band is left absent when that match is not valid.

At equal nominal rates, a **Hold** sawtooth is normally a beat pattern between
two free-running refresh cycles. The age of the newest guest frame ramps as
their phase moves, then wraps when a newer frame reaches the next client
deadline. This is not accumulated cross-VM clock error.

Configure the IDD with the physical display's exact refresh rate to minimize
this pattern. For example, use 119.970 Hz when that is the rate reported for
the display instead of rounding it to 120 Hz.

Investigate when Hold repeatedly exceeds roughly one guest frame period, or
when jumps occur with large Post, Copy or Ready spikes. Those patterns can
indicate server work or scheduling delays rather than normal phase drift.

Frame and photon summaries
--------------------------

The compact **FRAME** plot is the interval between completed client
render-and-swap loops. It includes cadence waits and cursor-only or overlay-only
redraws, so it is not the CPU time spent rendering one frame.

On Wayland compositors that support ``wp_presentation``, **PHOTON** measures
from immediately before the EGL swap request until the compositor reports
presentation. It includes Swap and must not be added to the stacked total. The
displayed reciprocal β€œHz” describes average latency, not the actual monitor
presentation rate.

Finding a bottleneck
--------------------

* High **Copy** points to guest GPU or system-memory bandwidth and the IDD copy
  path.
* High **Hold** alone usually reflects cadence phase; correlate it with other
  stages before changing anything.
* High **Import** with DMA disabled points to the client-side memory copy.
* High **Queue** can be intentional cadence or JIT waiting. Disable
  ``win:jitRender`` while diagnosing unstable timing.
* High **Effects**, **Desktop** or **Compose** points to client GPU rendering.
* A stable high **Swap** or **PHOTON** value can be expected when cadence
  matching waits for the correct presentation cycle. It does not by itself
  indicate an actual end-to-end latency increase. Investigate unexpected
  variation or missed cycles instead.

Keep the guest resolution and refresh realistic for the available memory
bandwidth. Reserve at least two physical CPU cores for Linux and avoid changing
poll intervals as a first response to a spike.

---

### Doc Quickstart (`doc/quickstart.rst`)

.. _quick_start:

Quick start
###########

This is the shortest path to a current Looking Glass installation. It assumes
that KVM/QEMU and the Windows guest are already working.

1. :doc:`Check the requirements <requirements>`.
2. :ref:`Download and build the Linux client `. Current
   releases are not provided as Linux distribution packages.
3. :doc:`Configure KVMFR and IVSHMEM ` for the largest guest
   resolution you intend to use.
4. :doc:`Install the matching Looking Glass IDD ` inside the
   Windows guest. Install the bundled IVSHMEM driver when required.
5. :doc:`Install the client ` from its build directory.
6. Start the Windows guest, then run:

   .. code:: bash

      looking-glass-client

The client selects ``/dev/kvmfr0`` automatically when it is present, and
otherwise uses ``/dev/shm/looking-glass``. If your path differs, select it with
``-f`` or ``lgmp:shmDevice``.

The first connection should show the virtual Looking Glass display created by
the IDD. If it does not, follow :doc:`the no-display checks
` before changing performance settings.

.. note::

   SPICE is optional for the primary IDD video and input paths. Keep it enabled
   if you want clipboard, audio or display fallback services.

---

### Doc Requirements (`doc/requirements.rst`)

.. _requirements:

Requirements and compatibility
##############################

.. _minimum:

Required
--------

Linux host
   A Linux system capable of running KVM/QEMU and building the Looking Glass
   Client. The client requires an EGL-capable graphics driver. X11 and Wayland
   are supported. For a responsive passthrough setup, use at least six CPU
   cores with twelve hardware threads.

Windows guest
   A Windows 10 version 1803 or newer, or Windows 11, virtual machine. The
   recommended IDD path can create its own virtual monitor and does not require
   a physical monitor or dummy plug.

Shared memory
   An IVSHMEM device large enough for the maximum guest resolution. The KVMFR
   kernel module is recommended and is required for direct GPU imports.

Matching components
   Use the current client, IDD and OBS plugin from the same Looking Glass
   release. A protocol version mismatch is not supported. Legacy Host users
   must use the complete matching B7 stack described below.

The IDD can fall back to software processing if the Windows guest has no
suitable render GPU. This is useful for compatibility, but hardware processing
is strongly recommended for lower latency and higher frame rates. Software
mode is SDR-only and does not provide the same performance as the GPU path.

.. _recommended:

Recommended
-----------

For a responsive high-resolution setup, use:

* a host CPU with eight cores and sixteen threads or better, with full
  performance cores around 3 GHz or faster;
* KVMFR rather than a plain shared-memory file;
* a host GPU and driver that support direct DMA imports;
* a hardware render adapter in the Windows guest; and
* enough memory bandwidth for the chosen resolution and refresh rate.

Do not assign every CPU core to the guest. Reserve at least two physical CPU
cores, or four threads, for Linux. Looking Glass, QEMU, the Linux desktop and
audio server all need host CPU time. High refresh rates also raise
shared-memory and GPU bandwidth requirements.

For a passed-through GPU, PCIe bandwidth can also limit performance. Use at
least eight PCIe 3.0 lanes or four PCIe 4.0 lanes where practical.

.. _connected_display:

Physical display and dummy plugs
--------------------------------

The recommended IDD does not require a physical display or dummy plug. It
creates a virtual Windows monitor, including on systems without a
passed-through display output.

A physical display, dummy plug or another virtual monitor is only required
when using the :doc:`legacy Host Application `, because that
application captures an existing Windows display.

.. _igpu_kvmfr_recommended:

Host GPU notes
--------------

AMD and Intel host GPUs commonly support the DMA-BUF path used by KVMFR. This
can reduce CPU work and avoid an extra system-memory copy. It is particularly
important for integrated GPUs, which already share memory bandwidth with the
CPU.

NVIDIA host GPUs require a driver configuration that supports DMA-BUF import.
If direct import is unavailable, the client falls back to a software copy.
Looking Glass still works, but uses more CPU and memory bandwidth.

Windows and HDR
---------------

Windows 10 remains supported. Current HDR and wide-color-gamut display features
depend on newer IddCx interfaces that the driver checks at runtime, so they are
normally available only on a compatible Windows 11 installation. The IDD
continues to use its SDR-compatible path when those interfaces are unavailable.

Native HDR presentation on Linux requires the EGL renderer, Wayland
``color-management-v1`` support in the compositor, and an HDR-capable output.
When native HDR is unavailable, the client can map HDR content to SDR.

---

### Doc Tech Faq (`doc/tech_faq.rst`)

Technical notes
###############

This page explains a few implementation choices. It is not required for normal
installation.

.. _ivshmemshared_ram:

IVSHMEM and shared memory
-------------------------

.. _what_exactly_is_the_ivshmem_device:

What is the IVSHMEM device?
~~~~~~~~~~~~~~~~~~~~~~~~~~~

IVSHMEM maps the same reserved memory into QEMU, the Windows guest and Linux.
KVMFR provides the Linux character-device interface used by the client and OBS
and can export regions for direct GPU import.

The IDD stores frame queues, frame metadata, pointer updates and input protocol
state in this region. It uses three frame buffers so a server and multiple
clients can progress without overwriting a frame that is still in use.

.. _what_is_the_ivshmem_device_being_used_for:

Why is the allocation larger than one image?

In addition to three aligned images, the region contains LGMP queues and GPU
resource alignment. Use :ref:libvirt_determining_memory rather than
multiplying width and height once.

.. _why_do_you_need_the_mouse_positional_information:

Why are there both absolute and relative mouse paths?

text
Desktop interaction needs absolute positioning so the host and guest pointers
stay aligned without capture. Games that lock the cursor need unbounded
relative movement. The IDD exposes both and the client selects the appropriate
path when capture mode changes.

SPICE fallback remains relative-only. Pointer position messages are also used
to render the guest cursor independently from desktop frame updates.

.. _why_does_lg_poll_for_updates_instead_of_using_interrupts:

Why does Looking Glass poll for updates?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Polling avoids the high overhead and batching behavior seen with virtual
interrupts, especially for high-rate pointer updates. The polling intervals
are configurable for diagnosis, but lowering them without evidence increases
CPU usage and does not guarantee lower latency.

How does cadence reduce bandwidth?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Clients publish their presentation period and deadline in the shared protocol.
The IDD prepares guest frames as they arrive, but transports only the newest
frame needed for the fastest active consumer. Other consumers independently
select the newest frame appropriate for their own rate. Clock-domain feedback
is exchanged as periods and deadlines rather than comparing raw timestamps
from Windows and Linux.

---

### Doc Troubleshooting (`doc/troubleshooting.rst`)

Troubleshooting
###############

Start with the symptom below. Avoid changing polling, synchronization or
renderer options until the basic server, shared-memory and version checks
pass.

.. toctree::
   :maxdepth: 1

   idd_diagnostics

.. _when_launching_looking_glass_the_desktop_doesnt_appear:

The Looking Glass monitor is missing in Windows
-----------------------------------------------

1. Confirm that the guest runs Windows 10 version 1803 or newer, or Windows 11.
2. Confirm that the IDD installer completed and restart Windows if requested.
3. Open the IDD helper and its log directory. See :ref:`idd_diagnostics`.
4. In ``looking-glass-idd.txt``, confirm that IVSHMEM opened with the expected
   size and that at least one configured display mode fits.
5. Increase IVSHMEM if every suitable mode was filtered. Restart the VM after
   changing its size.
6. Ensure the legacy Host service is disabled. Only one Looking Glass Server
   implementation should use the Looking Glass IVSHMEM device.

A missing passed-through GPU does not by itself prevent the IDD display from
appearing. The IDD can start in software mode, although that mode is slower and
SDR-only.

The client remains on the waiting screen
----------------------------------------

* Confirm that the Windows Looking Glass monitor is active and producing a
  desktop.
* Check that the client selected the same KVMFR device or shared-memory file as
  the VM.
* Confirm that the Linux user has read and write access to that device.
* Use matching client and IDD releases. A KVMFR or LGMP protocol mismatch is a
  hard incompatibility.
* If ``/dev/kvmfr0`` is a regular file instead of a character device, stop the
  VM, remove that accidental file and load KVMFR before starting the VM again.

The image is slow or stutters
-----------------------------

Open the timing graphs with :kbd:`ScrLk` + :kbd:`T` and follow
:ref:`client_performance`. Also check:

* the IDD helper reports GPU acceleration rather than software processing;
* ``lgmp:allowDMA=yes`` is using a direct import when the host driver supports
  it;
* enough CPU cores remain available to Linux;
* the guest resolution and refresh do not exceed available memory bandwidth;
* the compositor is not adding an unexpected frame queue; and
* the fastest active client or OBS source is requesting the intended cadence.

Do not set the guest to an extreme refresh rate merely to raise UPS. The IDD
can acquire newer frames and skip superseded ones before transport, but the
guest still pays the cost of rendering them.

Keyboard or mouse input does not work
-------------------------------------

* Press :kbd:`ScrLk` + :kbd:`I` to ensure guest input is enabled.
* Check ``looking-glass-input.txt`` and the client's selected input provider.
* Only one LGMP client owns direct input. Close another controlling client if
  necessary.
* If SPICE video fallback is active, keep ``spice:input=yes``. The client uses
  the VM's default PS/2 keyboard and mouse and intentionally switches input
  with the video source.
* If ``input:captureOnly=yes``, press :kbd:`ScrLk` to enter capture mode.

See :ref:`client_input` for normal, automatic keyboard and capture modes.

.. _the_clipboard_is_not_working:

The clipboard is not working
----------------------------

-  **Is clipboard synchronization enabled?**

   -  Before you can copy or paste content between the guest and host,
      :ref:`clipboard
      synchronization <libvirt_clipboard_synchronization>`
      must be enabled.

-  **Did you install the Spice Guest Tools?**

   -  The `SPICE Guest Tools
      driver <https://www.spice-space.org/download.html>`_ must be installed
      inside the Windows guest to synchronize the clipboard.
      The download is labeled "spice-guest-tools".

      .. warning::

         Do **NOT** install the QEMU Guest Tools driver.
         These are not the same.

   -  **Is it installed twice?**

      -  The Spice VDAgent is available in both Spice Guest Tools, and
         standalone as a separate installer. Check your installed programs
         and uninstall the VDAgent if it's installed separately.

.. _keyboard_shortcuts_not_captured_on_gnome_wayland:

Keyboard shortcuts are not captured on GNOME Wayland
-----------------------------------------------------

Capture mode may fail to capture compositor shortcuts like
ALT+Tab or ALT+Middle Mouse - they go to GNOME instead of the guest VM.

When Looking Glass first requests to inhibit shortcuts, GNOME shows a
dialog asking for permission. If you clicked "Deny" (or dismissed the dialog),
GNOME permanently blocks the application and never shows the dialog again.

Use the ``flatpak`` command to view or grant the permission, this works even
if LookingGlass is not a Flatpak application, as GNOME stores these permissions
in Flatpak's database:

.. code:: bash

   flatpak permission-set gnome shortcuts-inhibitor looking-glass-client.desktop GRANTED

To verify the permission was set:

.. code:: bash

   flatpak permissions gnome shortcuts-inhibitor

USB audio does not appear or play
---------------------------------

* Confirm that the client was built with ``libusbredirparser-0.5`` version
  0.7.1 or newer.
* Add an unused SPICE **USB Redirector** device to the VM.
* Keep ``spice:enable=yes``, ``spice:audio=yes`` and
  ``spice:usbAudio=yes``.
* In Windows Sound settings, select the Looking Glass USB Audio speakers as
  the output device.
* Check the client startup log. If USB audio creation failed before
  connection, Looking Glass falls back to classic SPICE audio and reports why.

The microphone is unavailable
------------------------------

The current PipeWire backend supports recording; the PulseAudio backend does
not. Ensure the client selected PipeWire, then check ``audio:micDefault`` and
the microphone indicator. Press :kbd:`ScrLk` + :kbd:`C` to change the default
permission and :kbd:`ScrLk` + :kbd:`E` to toggle recording.

---

### Doc Usage (`doc/usage.rst`)

.. _client_usage:

Use the client
##############

Start the client after the Windows guest and IDD are running:

.. code:: bash

   looking-glass-client

The client uses LGMP over ``/dev/kvmfr0`` automatically when that device is
available. Otherwise it uses ``/dev/shm/looking-glass``. Select another device
with ``-f`` or the canonical ``lgmp:shmDevice`` option:

.. code:: bash

   looking-glass-client -f /dev/kvmfr1

Use ``looking-glass-client --help`` to see the options supported by the
installed build. Command-line options override configuration files.

.. _client_key_bindings:

Default key bindings
--------------------

Looking Glass uses :kbd:`ScrLk` as its escape key by default. Press it by
itself to enter or leave capture mode. Hold it to display the available
commands. Change it with ``input:escapeKey`` or ``-m`` if the keyboard does
not have :kbd:`ScrLk`.

.. list-table:: Default client commands
   :widths: 35 65
   :header-rows: 1

   * - Command
     - Action
   * - :kbd:`ScrLk`
     - Enter or leave capture mode
   * - :kbd:`ScrLk` + :kbd:`Q`
     - Quit
   * - :kbd:`ScrLk` + :kbd:`F`
     - Toggle full screen
   * - :kbd:`ScrLk` + :kbd:`V`
     - Toggle the video stream
   * - :kbd:`ScrLk` + :kbd:`R`
     - Rotate clockwise by 90 degrees
   * - :kbd:`ScrLk` + :kbd:`Shift` + :kbd:`R`
     - Force guest display recovery mode
   * - :kbd:`ScrLk` + :kbd:`=`
     - Ask the IDD to match the client window resolution
   * - :kbd:`ScrLk` + :kbd:`I`
     - Toggle guest input
   * - :kbd:`ScrLk` + :kbd:`O`
     - Enter or leave interactive overlay mode
   * - :kbd:`ScrLk` + :kbd:`D`
     - Toggle the FPS and UPS widget
   * - :kbd:`ScrLk` + :kbd:`T`
     - Toggle the frame-timing graphs
   * - :kbd:`ScrLk` + :kbd:`N`
     - Toggle EGL night vision
   * - :kbd:`ScrLk` + :kbd:`E`
     - Toggle microphone recording when the audio backend supports it
   * - :kbd:`ScrLk` + :kbd:`C`
     - Cycle the default microphone permission
   * - :kbd:`ScrLk` + :kbd:`M`
     - Send mute to the guest
   * - :kbd:`ScrLk` + :kbd:`Up` or :kbd:`Down`
     - Send volume up or down to the guest
   * - :kbd:`ScrLk` + :kbd:`Insert` or :kbd:`Delete`
     - Adjust capture-mode mouse sensitivity
   * - :kbd:`ScrLk` + :kbd:`LWin` or :kbd:`RWin`
     - Send that Windows key to the guest
   * - :kbd:`ScrLk` + :kbd:`F1` through :kbd:`F12`
     - Send :kbd:`Ctrl` + :kbd:`Alt` + that function key to a Linux guest

The microphone commands are registered only when the client was built with
audio recording support. Night vision is an EGL feature. The virtual-console
bindings are registered only when the selected guest type is Linux.

.. _client_config_options_file:

Configuration files
-------------------

The client loads these files in order when they exist:

* ``/etc/looking-glass-client.ini``
* ``~/.looking-glass-client.ini``
* ``$XDG_CONFIG_HOME/looking-glass/client.ini``

Later files override earlier files. The usual per-user path is
``~/.config/looking-glass/client.ini``. Files use INI syntax:

.. code-block:: ini

   [win]
   fullScreen=yes
   setGuestRes=yes

   [input]
   autoCapture=yes

   [spice]
   clipboard=yes
   audio=yes

   [egl]
   preset=my-preset

Boolean values accept ``yes`` or ``no``. Long command-line options use
``section:name=value``, for example:

.. code:: bash

   looking-glass-client win:fullScreen=yes input:autoCapture=yes

.. _client_overlay_mode:
.. _client_config_widget:

Interactive overlay
-------------------

Press :kbd:`ScrLk` + :kbd:`O` to make the overlay interactive. Press
:kbd:`Esc` or the same binding to leave it. The overlay can:

* enable and arrange the FPS and timing widgets;
* select and configure EGL filters;
* save filter settings as presets; and
* enable diagnostic views such as damage rectangles.

Widget positions and sizes are stored in
``$XDG_CONFIG_HOME/looking-glass/imgui.ini``. EGL filter presets are stored in
``$XDG_CONFIG_HOME/looking-glass/presets``. Do not edit either while the
client is running.

Runtime changes are not all written to the main client configuration. Put
options that must apply at every start in ``client.ini``.

User guides
-----------

.. toctree::
   :maxdepth: 1

   input
   display
   audio
   performance
   options

---

### Doc Words (`doc/words.txt`)

Anime4K
backend
backends
backtrace
BigNavi
borderless
Brindus
cadence
cgroups
checkboxes
clang
cmake
codec
compositor
config
CopySleep
Debian
dejavu
deuteranope
dev
dir
DirectX
distros
dmabuf
dmesg
downsample
downsampling
downscaler
downscaling
EGL
evdev
ExtraMode
Flatpak
framebuffer
fullscreen
gcc
globalFullScreen
gnif
Guanzhong
HDR
hypervisor
i3
IddCx
ie
imgui
ini
kvmfr
laggy
lexically
libdecor
libpipewire
libpulse
libvirt
linux
LookingGlass
Losslessly
luminance
memballoon
MiB
microstutters
mingw
mipmapping
modprobe
mpv
msys
multisampling
namespace
Navi
NvFBC
Nvidia
overlayed
overrun
oversized
pacman
passthrough
performant
pre
prebuilt
protanope
QEMU
quadraphonic
Quadro
queueing
radeon
readback
realtime
renderer
repo
resampler
Rubenstein
runtime
scanout
Scream
scRGB
SDR
shaders
shm
spencercw
submodule
submodules
systemd
th
Threadripper
toolchain
tooltip
tritanope
tunable
uaccess
udev
UEFI
uncheck
uncomment
underrun
underruns
Unigine
unix
upscaled
upscaler
upscales
upscaling
viewport
VirtIO
virtio
VM
vsync
wayland
xdg
Xorg
xyene

---

--- METRICS ---
- Files Extracted: 32
- Estimated Token Budget: ~26744 tokens
- Canonical Reference: https://codewiki.google/github.com/gnif/LookingGlass