Compare commits

..

1 Commits

Author SHA1 Message Date
Quantum
04607d6139 [idd] helper: allow changing preferred mode 2026-06-03 19:45:23 -04:00
55 changed files with 185 additions and 1350 deletions

View File

@@ -13,7 +13,6 @@ find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
add_library(displayserver_Wayland STATIC
activation.c
clipboard.c
colormgmt.c
cursor.c
gl.c
idle.c

View File

@@ -1,110 +0,0 @@
/**
* Looking Glass
* Copyright (C) 2017-2026 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "wayland.h"
#include <stdbool.h>
#include <wayland-client.h>
#include "common/debug.h"
static void cmIntent(void * data, struct wp_color_manager_v1 * cm, uint32_t intent)
{
if (intent == WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL)
wlWm.cmHasPerceptualIntent = true;
}
static void cmFeature(void * data, struct wp_color_manager_v1 * cm, uint32_t feature)
{
switch (feature)
{
case WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC:
wlWm.cmHasParametric = true;
break;
case WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES:
wlWm.cmHasLuminances = true;
break;
case WP_COLOR_MANAGER_V1_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES:
wlWm.cmHasMasteringPrimaries = true;
break;
default:
break;
}
}
static void cmTFNamed(void * data, struct wp_color_manager_v1 * cm, uint32_t tf)
{
if (tf == WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ)
wlWm.cmHasTFSt2084PQ = true;
else if (tf == WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR)
wlWm.cmHasTFExtLinear = true;
}
static void cmPrimariesNamed(void * data, struct wp_color_manager_v1 * cm,
uint32_t primaries)
{
if (primaries == WP_COLOR_MANAGER_V1_PRIMARIES_BT2020)
wlWm.cmHasPrimariesBT2020 = true;
else if (primaries == WP_COLOR_MANAGER_V1_PRIMARIES_SRGB)
wlWm.cmHasPrimariesSRGB = true;
}
static void cmDone(void * data, struct wp_color_manager_v1 * cm)
{
wlWm.cmFeaturesDone = true;
wlWm.cmCanDoHDR = wlWm.cmHasParametric &&
((wlWm.cmHasTFSt2084PQ && wlWm.cmHasPrimariesBT2020) ||
(wlWm.cmHasTFExtLinear && wlWm.cmHasPrimariesSRGB));
DEBUG_INFO("Color management features: parametric:%d luminances:%d "
"mastering_primaries:%d st2084_pq:%d ext_linear:%d bt2020:%d srgb:%d "
"can_do_hdr:%d",
wlWm.cmHasParametric, wlWm.cmHasLuminances,
wlWm.cmHasMasteringPrimaries,
wlWm.cmHasTFSt2084PQ, wlWm.cmHasTFExtLinear,
wlWm.cmHasPrimariesBT2020, wlWm.cmHasPrimariesSRGB,
wlWm.cmCanDoHDR);
}
static const struct wp_color_manager_v1_listener cmListener = {
.supported_intent = cmIntent,
.supported_feature = cmFeature,
.supported_tf_named = cmTFNamed,
.supported_primaries_named = cmPrimariesNamed,
.done = cmDone,
};
bool waylandColorMgmtInit(void)
{
if (!wlWm.colorManager)
return true;
wp_color_manager_v1_add_listener(wlWm.colorManager, &cmListener, NULL);
return true;
}
void waylandColorMgmtFree(void)
{
if (!wlWm.colorManager)
return;
wp_color_manager_v1_destroy(wlWm.colorManager);
wlWm.colorManager = NULL;
}

View File

@@ -263,11 +263,6 @@ void libdecor_pollWait(struct wl_display * display, int epollFd,
}
}
bool libdecor_configured(void)
{
return state.configured;
}
WL_DesktopOps WLD_libdecor =
{
.name = "libdecor",
@@ -282,6 +277,5 @@ WL_DesktopOps WLD_libdecor =
.getSize = libdecor_getSize,
.registryGlobalHandler = libdecor_registryGlobalHandler,
.pollInit = libdecor_pollInit,
.pollWait = libdecor_pollWait,
.configured = libdecor_configured
.pollWait = libdecor_pollWait
};

View File

@@ -304,11 +304,6 @@ void xdg_pollWait(struct wl_display * display, int epollFd,
wl_display_cancel_read(display);
}
bool xdg_configured(void)
{
return state.configured;
}
WL_DesktopOps WLD_xdg =
{
.name = "xdg",
@@ -323,6 +318,5 @@ WL_DesktopOps WLD_xdg =
.getSize = xdg_getSize,
.registryGlobalHandler = xdg_registryGlobalHandler,
.pollInit = xdg_pollInit,
.pollWait = xdg_pollWait,
.configured = xdg_configured
.pollWait = xdg_pollWait
};

View File

@@ -70,52 +70,6 @@ EGLDisplay waylandGetEGLDisplay(void)
return eglGetDisplay(native);
}
static void applyHDRPending(void)
{
if (wlWm.pendingHDRApply)
{
wlWm.pendingHDRApply = false;
atomic_thread_fence(memory_order_acquire);
waylandSetHDRImageDescription(
wlWm.pendingHDRDisplayPrimary, wlWm.pendingHDRWhitePoint,
wlWm.pendingHDRMaxDisplayLuminance,
wlWm.pendingHDRMinDisplayLuminance,
wlWm.pendingHDRMaxCLL,
wlWm.pendingHDRMaxFALL,
wlWm.pendingHDRPQ);
}
else if (wlWm.pendingHDRClear)
{
wlWm.pendingHDRClear = false;
waylandClearHDRImageDescription();
}
}
void waylandClearHDRImageDescription(void)
{
if (!wlWm.hdrActive)
return;
if (wlWm.hdrImageCreator)
{
wp_image_description_creator_params_v1_destroy(wlWm.hdrImageCreator);
wlWm.hdrImageCreator = NULL;
}
if (wlWm.hdrImageDesc)
{
wp_image_description_v1_destroy(wlWm.hdrImageDesc);
wlWm.hdrImageDesc = NULL;
}
if (wlWm.colorSurface)
{
wp_color_management_surface_v1_destroy(wlWm.colorSurface);
wlWm.colorSurface = NULL;
}
wlWm.hdrActive = false;
DEBUG_INFO("HDR image description cleared");
}
void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct Rect * damage, int count)
{
if (!wlWm.swapWithDamage.init)
@@ -130,7 +84,6 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
}
waylandPresentationFrame();
applyHDRPending();
swapWithDamage(&wlWm.swapWithDamage, display, surface, damage, count);
if (wlWm.needsResize)
@@ -196,227 +149,23 @@ EGLNativeWindowType waylandGetEGLNativeWindow(void)
}
#endif
// HDR color management support
void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2],
const uint16_t whitePoint[2], uint32_t maxDisplayLuminance,
uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL,
bool hdrPQ)
{
if (!wlWm.colorManager)
return;
if (!wlWm.cmFeaturesDone)
{
DEBUG_WARN("Color management features not yet advertised, deferring HDR");
return;
}
if (!wlWm.cmHasParametric)
{
DEBUG_WARN("Compositor does not support parametric image descriptions");
return;
}
// Verify the compositor supports the transfer function we need
if (hdrPQ && !wlWm.cmHasTFSt2084PQ)
{
DEBUG_WARN("Compositor does not support ST2084_PQ transfer function");
return;
}
if (!hdrPQ && !wlWm.cmHasTFExtLinear)
{
DEBUG_WARN("Compositor does not support EXT_LINEAR transfer function");
return;
}
// Verify primaries support for the target color space
if (hdrPQ && !wlWm.cmHasPrimariesBT2020)
{
DEBUG_WARN("Compositor does not support BT.2020 primaries");
return;
}
if (!hdrPQ && !wlWm.cmHasPrimariesSRGB)
{
DEBUG_WARN("Compositor does not support sRGB primaries");
return;
}
// Clean up any previous description (allows re-application with updated metadata)
if (wlWm.hdrImageCreator)
{
wp_image_description_creator_params_v1_destroy(wlWm.hdrImageCreator);
wlWm.hdrImageCreator = NULL;
}
if (wlWm.hdrImageDesc)
{
wp_image_description_v1_destroy(wlWm.hdrImageDesc);
wlWm.hdrImageDesc = NULL;
}
if (wlWm.colorSurface)
{
wp_color_management_surface_v1_destroy(wlWm.colorSurface);
wlWm.colorSurface = NULL;
}
wlWm.hdrActive = false;
wlWm.hdrImageCreator =
wp_color_manager_v1_create_parametric_creator(wlWm.colorManager);
if (!wlWm.hdrImageCreator)
{
DEBUG_WARN("Failed to create parametric image description creator");
return;
}
// Set primaries: BT.2020 for PQ HDR10, sRGB for scRGB/FP16
wp_image_description_creator_params_v1_set_primaries_named(
wlWm.hdrImageCreator,
hdrPQ ? WP_COLOR_MANAGER_V1_PRIMARIES_BT2020
: WP_COLOR_MANAGER_V1_PRIMARIES_SRGB);
// Select transfer function: PQ for PQ-encoded content, linear for scRGB/FP16
wp_image_description_creator_params_v1_set_tf_named(
wlWm.hdrImageCreator,
hdrPQ ? WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ
: WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR);
// Set luminance range from metadata (values already in 0.0001 cd/m² units)
if (wlWm.cmHasLuminances)
wp_image_description_creator_params_v1_set_luminances(
wlWm.hdrImageCreator,
minDisplayLuminance > 0 ? minDisplayLuminance : 50,
maxDisplayLuminance > 0 ? maxDisplayLuminance : 10000000,
hdrPQ ? 2030000 : 800000);
// Set mastering display primaries from frame HDR metadata.
// Always set when the compositor supports it, falling back to the
// primaries from the metadata (even if zero, in which case the
// compositor uses its own defaults).
if (wlWm.cmHasMasteringPrimaries)
wp_image_description_creator_params_v1_set_mastering_display_primaries(
wlWm.hdrImageCreator,
displayPrimary[0][0], displayPrimary[0][1],
displayPrimary[1][0], displayPrimary[1][1],
displayPrimary[2][0], displayPrimary[2][1],
whitePoint[0], whitePoint[1]);
if (maxCLL > 0)
wp_image_description_creator_params_v1_set_max_cll(wlWm.hdrImageCreator, maxCLL);
if (maxFALL > 0)
wp_image_description_creator_params_v1_set_max_fall(wlWm.hdrImageCreator, maxFALL);
wlWm.hdrImageDesc =
wp_image_description_creator_params_v1_create(wlWm.hdrImageCreator);
wlWm.hdrImageCreator = NULL; // consumed by create
if (!wlWm.hdrImageDesc)
{
DEBUG_WARN("Failed to create HDR image description");
return;
}
wlWm.colorSurface =
wp_color_manager_v1_get_surface(wlWm.colorManager, wlWm.surface);
if (!wlWm.colorSurface)
{
DEBUG_WARN("Failed to get color management surface");
wp_image_description_v1_destroy(wlWm.hdrImageDesc);
wlWm.hdrImageDesc = NULL;
return;
}
wp_color_management_surface_v1_set_image_description(
wlWm.colorSurface, wlWm.hdrImageDesc,
WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
wlWm.hdrActive = true;
DEBUG_INFO("HDR image description set on surface (%s, %s, %u nits)",
hdrPQ ? "PQ" : "scRGB", hdrPQ ? "BT.2020" : "sRGB", maxDisplayLuminance);
}
bool waylandRequestHDR(const uint16_t displayPrimary[3][2],
const uint16_t whitePoint[2], uint32_t maxDisplayLuminance,
uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL,
bool hdrPQ)
{
if (!wlWm.cmFeaturesDone || !wlWm.cmHasParametric)
return false;
if (hdrPQ && !wlWm.cmHasTFSt2084PQ)
return false;
if (!hdrPQ && !wlWm.cmHasTFExtLinear)
return false;
if (hdrPQ && !wlWm.cmHasPrimariesBT2020)
return false;
if (!hdrPQ && !wlWm.cmHasPrimariesSRGB)
return false;
wlWm.pendingHDRPQ = hdrPQ;
// Write all metadata before setting the apply flag to ensure the
// render thread sees the complete HDR metadata when it observes
// pendingHDRApply == true.
memcpy(wlWm.pendingHDRDisplayPrimary, displayPrimary,
sizeof(wlWm.pendingHDRDisplayPrimary));
memcpy(wlWm.pendingHDRWhitePoint, whitePoint,
sizeof(wlWm.pendingHDRWhitePoint));
wlWm.pendingHDRMaxDisplayLuminance = maxDisplayLuminance;
wlWm.pendingHDRMinDisplayLuminance = minDisplayLuminance;
wlWm.pendingHDRMaxCLL = maxCLL;
wlWm.pendingHDRMaxFALL = maxFALL;
wlWm.pendingHDRClear = false;
atomic_thread_fence(memory_order_release);
wlWm.pendingHDRApply = true;
return true;
}
void waylandRequestClearHDR(void)
{
wlWm.pendingHDRClear = true;
wlWm.pendingHDRApply = false;
}
#ifdef ENABLE_OPENGL
static const EGLint eglBaseAttrs[] =
{
EGL_CONFORMANT , EGL_OPENGL_BIT,
EGL_RENDERABLE_TYPE , EGL_OPENGL_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_SAMPLE_BUFFERS , 0,
EGL_SAMPLES , 0,
EGL_NONE
};
static bool eglChooseConfigWithDepth(EGLDisplay display, EGLint red,
EGLint green, EGLint blue, EGLint alpha, EGLint depth,
EGLConfig * config, const char ** desc)
{
// Build attr array with the base attrs plus color depth
EGLint attr[32];
int ai = 0;
attr[ai++] = EGL_RED_SIZE ; attr[ai++] = red;
attr[ai++] = EGL_GREEN_SIZE; attr[ai++] = green;
attr[ai++] = EGL_BLUE_SIZE ; attr[ai++] = blue;
attr[ai++] = EGL_ALPHA_SIZE; attr[ai++] = alpha;
attr[ai++] = EGL_BUFFER_SIZE; attr[ai++] = depth;
for (int i = 0; eglBaseAttrs[i] != EGL_NONE; ++i)
attr[ai++] = eglBaseAttrs[i];
attr[ai] = EGL_NONE;
EGLint num_config;
if (eglChooseConfig(display, attr, config, 1, &num_config) && num_config > 0)
{
if (desc)
*desc = red >= 16 ? "FP16 (RGBA16F)" :
red >= 10 ? "10-bit (RGBA10)" : "8-bit (RGBA8)";
return true;
}
return false;
}
bool waylandOpenGLInit(void)
{
EGLint attr[] =
{
EGL_BUFFER_SIZE , 24,
EGL_CONFORMANT , EGL_OPENGL_BIT,
EGL_RENDERABLE_TYPE , EGL_OPENGL_BIT,
EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
EGL_RED_SIZE , 8,
EGL_GREEN_SIZE , 8,
EGL_BLUE_SIZE , 8,
EGL_SAMPLE_BUFFERS , 0,
EGL_SAMPLES , 0,
EGL_NONE
};
wlWm.glDisplay = waylandGetEGLDisplay();
int maj, min;
@@ -432,31 +181,13 @@ bool waylandOpenGLInit(void)
return false;
}
EGLConfig config;
const char * configDesc = NULL;
// Probe for best available color depth: FP16 → 10-bit → 8-bit
if (!eglChooseConfigWithDepth(wlWm.glDisplay,
16, 16, 16, 0, 48, &config, &configDesc) &&
!eglChooseConfigWithDepth(wlWm.glDisplay,
10, 10, 10, 2, 32, &config, &configDesc) &&
!eglChooseConfigWithDepth(wlWm.glDisplay,
8, 8, 8, 0, 24, &config, &configDesc))
EGLint num_config;
if (!eglChooseConfig(wlWm.glDisplay, attr, &wlWm.glConfig, 1, &num_config))
{
DEBUG_ERROR("Failed to choose any EGL config");
DEBUG_ERROR("Failed to choose config (eglError: 0x%x)", eglGetError());
return false;
}
wlWm.glConfig = config;
DEBUG_INFO("EGL config: %s", configDesc);
// Also store the 8-bit fallback for SDR contexts
if (configDesc && strcmp(configDesc, "8-bit (RGBA8)") != 0)
eglChooseConfigWithDepth(wlWm.glDisplay,
8, 8, 8, 0, 24, &wlWm.glConfigSDR, NULL);
else
wlWm.glConfigSDR = wlWm.glConfig;
wlWm.glSurface = eglCreateWindowSurface(wlWm.glDisplay, wlWm.glConfig, wlWm.eglWindow, NULL);
if (wlWm.glSurface == EGL_NO_SURFACE)
{

View File

@@ -58,8 +58,6 @@ typedef struct WL_DesktopOps
bool (*pollInit)(struct wl_display * display);
void (*pollWait)(struct wl_display * display, int epollFd, unsigned int time);
bool (*configured)(void);
}
WL_DesktopOps;

View File

@@ -60,15 +60,6 @@ wayland_generate(
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/fractional-scale/fractional-scale-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-fractional-scale-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/content-type/content-type-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-content-type-v1-client-protocol")
wayland_generate(
"${WAYLAND_PROTOCOLS_BASE}/staging/color-management/color-management-v1.xml"
"${CMAKE_BINARY_DIR}/wayland/wayland-color-management-v1-client-protocol")
target_link_libraries(wayland_protocol
PkgConfig::WAYLAND

View File

@@ -46,9 +46,6 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
else if (!strcmp(interface, wp_viewporter_interface.name))
wlWm.viewporter = wl_registry_bind(wlWm.registry, name,
&wp_viewporter_interface, 1);
else if (!strcmp(interface, wp_fractional_scale_manager_v1_interface.name))
wlWm.fractionalScaleManager = wl_registry_bind(wlWm.registry, name,
&wp_fractional_scale_manager_v1_interface, 1);
else if (!strcmp(interface, zwp_relative_pointer_manager_v1_interface.name))
wlWm.relativePointerManager = wl_registry_bind(wlWm.registry, name,
&zwp_relative_pointer_manager_v1_interface, 1);
@@ -71,12 +68,6 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
else if (!strcmp(interface, xdg_activation_v1_interface.name))
wlWm.xdgActivation = wl_registry_bind(wlWm.registry, name,
&xdg_activation_v1_interface, 1);
else if (!strcmp(interface, wp_content_type_manager_v1_interface.name))
wlWm.contentTypeManager = wl_registry_bind(wlWm.registry, name,
&wp_content_type_manager_v1_interface, 1);
else if (!strcmp(interface, wp_color_manager_v1_interface.name))
wlWm.colorManager = wl_registry_bind(wlWm.registry, name,
&wp_color_manager_v1_interface, 1);
else if (wlWm.desktop->registryGlobalHandler(
data, registry, name, interface, version))
return;

View File

@@ -71,7 +71,7 @@ static inline int waylandScaleCeil(struct WaylandScale scale)
static inline int waylandScaleMulInt(struct WaylandScale scale, int value)
{
return (int)(((int64_t)value * scale.num + scale.den / 2) / scale.den);
return (int)(((int64_t)value * scale.num) / scale.den);
}
static inline double waylandScaleToDouble(struct WaylandScale scale)

View File

@@ -28,7 +28,6 @@
#include "common/debug.h"
#include "common/option.h"
#include "interface/renderer.h"
#include "dynamic/wayland_desktops.h"
@@ -144,9 +143,6 @@ static bool waylandInit(const LG_DSInitParams params)
if (!waylandRegistryInit())
return false;
if (!waylandColorMgmtInit())
return false;
if (!waylandActivationInit())
return false;
@@ -193,7 +189,6 @@ static void waylandFree(void)
waylandPresentationFree();
waylandInputFree();
waylandOutputFree();
waylandColorMgmtFree();
waylandRegistryFree();
waylandCursorFree();
wl_display_disconnect(wlWm.display);
@@ -207,12 +202,6 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret)
return true;
}
if (prop == LG_DS_NATIVE_HDR)
{
*(bool *)ret = wlWm.cmCanDoHDR;
return true;
}
return false;
}
@@ -238,22 +227,6 @@ static void waylandMinimize(void)
wlWm.desktop->minimize();
}
static bool waylandHDRCallback(const void * rendererFormat)
{
if (!wlWm.colorManager)
return false;
const LG_RendererFormat * format = (const LG_RendererFormat *)rendererFormat;
if (format->hdr)
return waylandRequestHDR(format->hdrDisplayPrimary, format->hdrWhitePoint,
format->hdrMaxDisplayLuminance, format->hdrMinDisplayLuminance,
format->hdrMaxContentLightLevel, format->hdrMaxFrameAverageLightLevel,
format->hdrPQ);
else
waylandRequestClearHDR();
return true;
}
struct LG_DisplayServerOps LGDS_Wayland =
{
.name = "Wayland",
@@ -303,8 +276,6 @@ struct LG_DisplayServerOps LGDS_Wayland =
.getFullscreen = waylandGetFullscreen,
.minimize = waylandMinimize,
.setHDRImageDescription = waylandHDRCallback,
.cbInit = waylandCBInit,
.cbNotice = waylandCBNotice,
.cbRelease = waylandCBRelease,

View File

@@ -47,9 +47,6 @@
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
#include "wayland-xdg-output-unstable-v1-client-protocol.h"
#include "wayland-xdg-activation-v1-client-protocol.h"
#include "wayland-fractional-scale-v1-client-protocol.h"
#include "wayland-content-type-v1-client-protocol.h"
#include "wayland-color-management-v1-client-protocol.h"
#include "scale.h"
@@ -86,6 +83,13 @@ struct SurfaceOutput
struct wl_list link;
};
enum EGLSwapWithDamageState {
SWAP_WITH_DAMAGE_UNKNOWN,
SWAP_WITH_DAMAGE_UNSUPPORTED,
SWAP_WITH_DAMAGE_KHR,
SWAP_WITH_DAMAGE_EXT,
};
struct xkb_context;
struct xkb_keymap;
struct xkb_state;
@@ -121,8 +125,7 @@ struct WaylandDSState
#ifdef ENABLE_OPENGL
EGLDisplay glDisplay;
EGLConfig glConfig; // primary config (best bit depth probed)
EGLConfig glConfigSDR; // fallback 8-bit SDR config
EGLConfig glConfig;
EGLSurface glSurface;
#endif
@@ -172,52 +175,11 @@ struct WaylandDSState
struct wp_viewporter * viewporter;
struct wp_viewport * viewport;
struct wp_fractional_scale_manager_v1 * fractionalScaleManager;
struct wp_fractional_scale_v1 * fractionalScaleInterface;
struct zxdg_output_manager_v1 * xdgOutputManager;
struct wl_list outputs; // WaylandOutput::link
struct wl_list surfaceOutputs; // SurfaceOutput::link
bool useFractionalScale;
struct wp_content_type_manager_v1 * contentTypeManager;
struct wp_content_type_v1 * contentType;
// Color management (HDR)
struct wp_color_manager_v1 * colorManager;
struct wp_color_management_surface_v1 * colorSurface;
struct wp_image_description_v1 * hdrImageDesc;
struct wp_image_description_creator_params_v1 * hdrImageCreator;
// Set to true when an HDR image description is active on the surface
bool hdrActive;
// wp_color_manager_v1 feature advertisement tracking.
// Set to true after the done event for the color-manager has been received
// and all compositor capabilities have been recorded.
bool cmFeaturesDone;
bool cmHasParametric;
bool cmHasLuminances;
bool cmHasMasteringPrimaries;
bool cmHasTFSt2084PQ;
bool cmHasTFExtLinear;
bool cmHasPrimariesBT2020;
bool cmHasPrimariesSRGB;
bool cmHasPerceptualIntent;
bool cmCanDoHDR; // true if compositor supports features needed for HDR
// Pending HDR format to apply (set by frame thread, applied in swap buffers).
// pendingHDRApply and pendingHDRClear are accessed from multiple threads
// without a lock, so they must be atomic.
_Atomic(bool) pendingHDRApply;
_Atomic(bool) pendingHDRClear;
bool pendingHDRPQ;
uint16_t pendingHDRDisplayPrimary[3][2];
uint16_t pendingHDRWhitePoint[2];
uint32_t pendingHDRMaxDisplayLuminance;
uint32_t pendingHDRMinDisplayLuminance;
uint32_t pendingHDRMaxCLL;
uint32_t pendingHDRMaxFALL;
LGEvent * frameEvent;
struct wl_list poll; // WaylandPoll::link
@@ -300,24 +262,6 @@ void waylandGLSetSwapInterval(int interval);
void waylandGLSwapBuffers(void);
#endif
// HDR color management (Wayland color-management-v1)
bool waylandColorMgmtInit(void);
void waylandColorMgmtFree(void);
void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2],
const uint16_t whitePoint[2], uint32_t maxDisplayLuminance,
uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL,
bool hdrPQ);
void waylandClearHDRImageDescription(void);
// Queue HDR change from any thread (applied in waylandEGLSwapBuffers).
// Returns true if the request was queued, false if HDR is not available
// (no color manager, missing features, or unsupported TF/primaries).
bool waylandRequestHDR(const uint16_t displayPrimary[3][2],
const uint16_t whitePoint[2], uint32_t maxDisplayLuminance,
uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL,
bool hdrPQ);
void waylandRequestClearHDR(void);
// idle module
bool waylandIdleInit(void);
void waylandIdleFree(void);

View File

@@ -31,25 +31,8 @@
// Surface-handling listeners.
static void setScale(struct WaylandScale newScale)
{
wlWm.scale = newScale;
wlWm.fractionalScale = waylandScaleIsFractional(newScale);
wlWm.needsResize = true;
if (wlWm.desktop->configured())
{
waylandCursorScaleChange();
app_invalidateWindow(true);
waylandStopWaitFrame();
}
}
void waylandWindowUpdateScale(void)
{
if (wlWm.fractionalScaleInterface)
return;
struct WaylandScale maxScale = waylandScaleFromInt(0);
struct SurfaceOutput * node;
@@ -61,7 +44,14 @@ void waylandWindowUpdateScale(void)
}
if (waylandScaleValid(maxScale))
setScale(maxScale);
{
wlWm.scale = maxScale;
wlWm.fractionalScale = waylandScaleIsFractional(maxScale);
wlWm.needsResize = true;
waylandCursorScaleChange();
app_invalidateWindow(true);
waylandStopWaitFrame();
}
}
static void wlSurfaceEnterHandler(void * data, struct wl_surface * surface, struct wl_output * output)
@@ -95,16 +85,6 @@ static const struct wl_surface_listener wlSurfaceListener = {
.leave = wlSurfaceLeaveHandler,
};
static void fractionalScalePreferredScale(void * data,
struct wp_fractional_scale_v1 * fractionalScale, uint32_t scale)
{
setScale(waylandScaleFromRatio(scale, 120));
}
static const struct wp_fractional_scale_v1_listener fractionalScaleListener = {
.preferred_scale = fractionalScalePreferredScale,
};
bool waylandWindowInit(const char * title, const char * appId, bool fullscreen, bool maximize, bool borderless, bool resizable)
{
wlWm.scale = waylandScaleFromInt(1);
@@ -130,22 +110,7 @@ bool waylandWindowInit(const char * title, const char * appId, bool fullscreen,
return false;
}
if (wlWm.fractionalScaleManager)
{
wlWm.fractionalScaleInterface = wp_fractional_scale_manager_v1_get_fractional_scale(
wlWm.fractionalScaleManager, wlWm.surface);
wp_fractional_scale_v1_add_listener(wlWm.fractionalScaleInterface,
&fractionalScaleListener, NULL);
}
else
wl_surface_add_listener(wlWm.surface, &wlSurfaceListener, NULL);
if (wlWm.contentTypeManager)
{
wlWm.contentType = wp_content_type_manager_v1_get_surface_content_type(
wlWm.contentTypeManager, wlWm.surface);
wp_content_type_v1_set_content_type(wlWm.contentType, WP_CONTENT_TYPE_V1_TYPE_GAME);
}
wl_surface_add_listener(wlWm.surface, &wlSurfaceListener, NULL);
if (!wlWm.desktop->shellInit(wlWm.display, wlWm.surface,
title, appId, fullscreen, maximize, borderless, resizable))
@@ -157,10 +122,6 @@ bool waylandWindowInit(const char * title, const char * appId, bool fullscreen,
void waylandWindowFree(void)
{
if (wlWm.fractionalScaleInterface)
wp_fractional_scale_v1_destroy(wlWm.fractionalScaleInterface);
if (wlWm.contentType)
wp_content_type_v1_destroy(wlWm.contentType);
wl_surface_destroy(wlWm.surface);
lgFreeEvent(wlWm.frameEvent);
}

View File

@@ -72,13 +72,6 @@ void app_setFullscreen(bool fs);
bool app_getFullscreen(void);
bool app_getProp(LG_DSProperty prop, void * ret);
/**
* Returns true if the last call to setHDRImageDescription() failed.
* When this returns true, the renderer should fall back to software
* tone-mapping even on a compositor that reports LG_DS_NATIVE_HDR.
*/
bool app_getHDRDescFailed(void);
#ifdef ENABLE_EGL
EGLDisplay app_getEGLDisplay(void);
EGLNativeWindowType app_getEGLNativeWindow(void);

View File

@@ -53,14 +53,6 @@ typedef enum LG_DSProperty
* return data type: bool
*/
LG_DS_WARP_SUPPORT,
/**
* returns true if the display server supports native HDR via
* setHDRImageDescription (i.e., the compositor actually has the
* required color-management features to process HDR content).
* return data type: bool
*/
LG_DS_NATIVE_HDR,
}
LG_DSProperty;
@@ -221,13 +213,6 @@ struct LG_DisplayServerOps
void (*setFullscreen)(bool fs);
void (*minimize)(void);
/* HDR color management - set display image description.
* Optional, if not supported set to NULL.
* Returns true on success, false if the description could not be applied
* (e.g., compositor doesn't support the required transfer function or
* primaries, or the image description creation failed). */
bool (*setHDRImageDescription)(const void * rendererFormat);
/* clipboard support, optional, if not supported set to NULL */
bool (*cbInit)(void);
void (*cbNotice)(LG_ClipboardData type);

View File

@@ -84,14 +84,6 @@ typedef struct LG_RendererFormat
unsigned int pitch; // scanline bytes (or compressed size)
unsigned int bpp; // bits per pixel (zero if compressed)
LG_RendererRotate rotate; // guest rotation
// HDR static metadata (from KVMFRFrame, valid when hdr is true)
uint16_t hdrDisplayPrimary[3][2];
uint16_t hdrWhitePoint[2];
uint32_t hdrMaxDisplayLuminance;
uint32_t hdrMinDisplayLuminance;
uint32_t hdrMaxContentLightLevel;
uint32_t hdrMaxFrameAverageLightLevel;
}
LG_RendererFormat;

View File

@@ -91,7 +91,6 @@ struct EGL_Desktop
// map HDR content to SDR
bool mapHDRtoSDR;
bool nativeHDR;
int peakLuminance;
int maxCLL;
@@ -549,7 +548,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uCBMode,
.i = { desktop->cbMode }
.f = { desktop->cbMode }
},
{
.type = EGL_UNIFORM_TYPE_1I,
@@ -559,7 +558,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uMapHDRtoSDR,
.i = { desktop->mapHDRtoSDR && !desktop->nativeHDR }
.i = { desktop->mapHDRtoSDR }
},
{
.type = EGL_UNIFORM_TYPE_1F,
@@ -569,7 +568,7 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
{
.type = EGL_UNIFORM_TYPE_1I,
.location = shader->uMapHDRPQ,
.i = { desktop->hdrPQ }
.f = { desktop->hdrPQ }
}
};
@@ -580,11 +579,6 @@ bool egl_desktopRender(EGL_Desktop * desktop, unsigned int outputWidth,
return true;
}
void egl_desktopSetNativeHDR(EGL_Desktop * desktop, bool nativeHDR)
{
desktop->nativeHDR = nativeHDR;
}
void egl_desktopSpiceConfigure(EGL_Desktop * desktop, int width, int height)
{
if (!desktop->spiceTexture)

View File

@@ -42,7 +42,6 @@ bool egl_desktopInit(EGL * egl, EGL_Desktop ** desktop, EGLDisplay * display,
void egl_desktopFree(EGL_Desktop ** desktop);
void egl_desktopConfigUI(EGL_Desktop * desktop);
void egl_desktopSetNativeHDR(EGL_Desktop * desktop, bool nativeHDR);
bool egl_desktopSetup (EGL_Desktop * desktop, const LG_RendererFormat format);
bool egl_desktopUpdate(EGL_Desktop * desktop, const FrameBuffer * frame, int dmaFd,
const FrameDamageRect * damageRects, int damageRectsCount);

View File

@@ -121,9 +121,6 @@ struct Inst
bool showSpice;
int spiceWidth, spiceHeight;
bool configSupportsHDR; // true if we probed FP16 or 10-bit EGL config
bool hdr; // true if current frame format is HDR
};
static struct Option egl_options[] =
@@ -610,26 +607,6 @@ static bool egl_onFrameFormat(LG_Renderer * renderer, const LG_RendererFormat fo
egl_cursorSetScale(this->cursor, scale);
}
// Track HDR state and warn if HDR frames arrive without any HDR path
this->hdr = format.hdr;
if (format.hdr)
{
bool nativeHDR = false;
app_getProp(LG_DS_NATIVE_HDR, &nativeHDR);
if (!this->configSupportsHDR && !nativeHDR)
DEBUG_WARN("HDR frames being displayed on an 8-bit EGL surface "
"without a color-managed compositor; tones may be incorrect");
}
// If the display server supports native HDR (via setHDRImageDescription),
// disable software tone-mapping to avoid double tone-mapping.
// However, if the last call to setHDRImageDescription actually failed
// (e.g., compositor missing required primaries), keep tone-mapping on.
bool nativeHDR = false;
app_getProp(LG_DS_NATIVE_HDR, &nativeHDR);
egl_desktopSetNativeHDR(this->desktop,
format.hdr && nativeHDR && !app_getHDRDescFailed());
egl_update_scale_type(this);
egl_damageSetup(this->damage, format.frameWidth, format.frameHeight);
@@ -797,51 +774,22 @@ static bool egl_renderStartup(LG_Renderer * renderer, bool useDMA)
}
}
// Probe for best available color depth: FP16 → 10-bit → 8-bit
static const struct { EGLint r, g, b, a, depth; const char * desc; } configs[] =
EGLint attr[] =
{
{ 16, 16, 16, 0, 48, "FP16 (RGBA16F)" },
{ 10, 10, 10, 2, 32, "10-bit (RGBA10)" },
{ 8, 8, 8, 0, 24, "8-bit (RGBA8)" },
EGL_BUFFER_SIZE , 30,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
EGL_SAMPLES , maxSamples,
EGL_NONE
};
EGLint num_config;
const char * configDesc = NULL;
int chosen = -1;
for (int i = 0; i < (int)(sizeof(configs) / sizeof(configs[0])); ++i)
EGLint num_config;
if (!eglChooseConfig(this->display, attr, &this->configs, 1, &num_config))
{
EGLint attr[] =
{
EGL_RED_SIZE , configs[i].r,
EGL_GREEN_SIZE , configs[i].g,
EGL_BLUE_SIZE , configs[i].b,
EGL_ALPHA_SIZE , configs[i].a,
EGL_BUFFER_SIZE , configs[i].depth,
EGL_RENDERABLE_TYPE , EGL_OPENGL_ES2_BIT,
EGL_SAMPLE_BUFFERS , maxSamples > 0 ? 1 : 0,
EGL_SAMPLES , maxSamples,
EGL_NONE
};
if (eglChooseConfig(this->display, attr, &this->configs, 1, &num_config) &&
num_config > 0)
{
configDesc = configs[i].desc;
chosen = i;
break;
}
}
if (chosen < 0)
{
DEBUG_ERROR("Failed to choose any EGL config");
DEBUG_ERROR("Failed to choose config (eglError: 0x%x)", eglGetError());
return false;
}
this->configSupportsHDR = chosen <= 1; // FP16 or 10-bit
DEBUG_INFO("EGL config: %s%s", configDesc,
this->configSupportsHDR ? " (HDR capable)" : "");
const EGLint surfattr[] =
{
EGL_RENDER_BUFFER, this->opt.doubleBuffer ? EGL_BACK_BUFFER : EGL_SINGLE_BUFFER,

View File

@@ -618,11 +618,6 @@ bool app_getProp(LG_DSProperty prop, void * ret)
return g_state.ds->getProp(prop, ret);
}
bool app_getHDRDescFailed(void)
{
return atomic_load(&g_state.hdrDescFailed);
}
#ifdef ENABLE_EGL
EGLDisplay app_getEGLDisplay(void)
{

View File

@@ -221,8 +221,8 @@ void core_updatePositionInfo(void)
.type = LG_MSG_WINDOWSIZE,
.windowSize =
{
.width = round(g_state.windowW * g_state.windowScale),
.height = round(g_state.windowH * g_state.windowScale)
.width = g_state.windowW,
.height = g_state.windowH
}
};
lgMessage_post(&msg);

View File

@@ -641,25 +641,6 @@ int main_frameThread(void * unused)
lgrFormat.hdr = frame->flags & FRAME_FLAG_HDR;
lgrFormat.hdrPQ = frame->flags & FRAME_FLAG_HDR_PQ;
if (lgrFormat.hdr)
{
memcpy(lgrFormat.hdrDisplayPrimary, frame->hdrDisplayPrimary, sizeof(lgrFormat.hdrDisplayPrimary));
memcpy(lgrFormat.hdrWhitePoint , frame->hdrWhitePoint , sizeof(lgrFormat.hdrWhitePoint ));
lgrFormat.hdrMaxDisplayLuminance = frame->hdrMaxDisplayLuminance;
lgrFormat.hdrMinDisplayLuminance = frame->hdrMinDisplayLuminance;
lgrFormat.hdrMaxContentLightLevel = frame->hdrMaxContentLightLevel;
lgrFormat.hdrMaxFrameAverageLightLevel = frame->hdrMaxFrameAverageLightLevel;
}
else
{
memset(lgrFormat.hdrDisplayPrimary, 0, sizeof(lgrFormat.hdrDisplayPrimary));
memset(lgrFormat.hdrWhitePoint , 0, sizeof(lgrFormat.hdrWhitePoint ));
lgrFormat.hdrMaxDisplayLuminance = 0;
lgrFormat.hdrMinDisplayLuminance = 0;
lgrFormat.hdrMaxContentLightLevel = 0;
lgrFormat.hdrMaxFrameAverageLightLevel = 0;
}
if (frame->flags & FRAME_FLAG_TRUNCATED)
{
const float needed =
@@ -747,17 +728,6 @@ int main_frameThread(void * unused)
}
LG_UNLOCK(g_state.lgrLock);
if (g_state.ds->setHDRImageDescription)
{
if (!g_state.ds->setHDRImageDescription(&lgrFormat))
{
DEBUG_WARN("Display server failed to apply HDR image description");
atomic_store(&g_state.hdrDescFailed, true);
}
else
atomic_store(&g_state.hdrDescFailed, false);
}
g_state.srcSize.x = lgrFormat.screenWidth;
g_state.srcSize.y = lgrFormat.screenHeight;
g_state.haveSrcSize = true;
@@ -1468,7 +1438,6 @@ static int lg_run(void)
core_setGrab(true);
uint32_t udataSize;
uint32_t remoteVersion;
KVMFR *udata;
int waitCount = 0;
@@ -1493,7 +1462,7 @@ restart:
}
status = lgmpClientSessionInit(g_state.lgmp, &udataSize, (uint8_t **)&udata,
NULL, &remoteVersion);
NULL);
switch(status)
{
case LGMP_OK:
@@ -1511,8 +1480,6 @@ restart:
"Please download and install the matching version."
);
DEBUG_INFO("LGMP host:%u client:%u",
remoteVersion, LGMP_PROTOCOL_VERSION);
DEBUG_INFO("Waiting for you to upgrade the host application");
}

View File

@@ -154,11 +154,6 @@ struct AppState
enum MicDefaultState micDefaultState;
int spiceHotX, spiceHotY;
// Set to true when setHDRImageDescription() returns false, indicating
// the display server could not apply the HDR image description.
// Checked by the renderer to fall back to software tone-mapping.
_Atomic(bool) hdrDescFailed;
};
struct AppParams

View File

@@ -162,15 +162,6 @@ typedef struct KVMFRFrame
uint32_t damageRectsCount; // the number of damage rectangles (zero for full-frame damage)
FrameDamageRect damageRects[KVMFR_MAX_DAMAGE_RECTS];
KVMFRFrameFlags flags; // bit field combination of FRAME_FLAG_*
// HDR static metadata (valid when FRAME_FLAG_HDR is set)
// Display color primaries in 0.00002 units (SMPTE ST 2086 format)
uint16_t hdrDisplayPrimary[3][2]; // Rx,Ry, Gx,Gy, Bx,By
uint16_t hdrWhitePoint[2]; // Wx, Wy
uint32_t hdrMaxDisplayLuminance; // Max mastering display luminance (0.0001 cd/m²)
uint32_t hdrMinDisplayLuminance; // Min mastering display luminance (0.0001 cd/m²)
uint32_t hdrMaxContentLightLevel; // MaxCLL (cd/m²)
uint32_t hdrMaxFrameAverageLightLevel; // MaxFALL (cd/m²)
}
KVMFRFrame;

View File

@@ -105,6 +105,7 @@ feature is disabled when running :ref:`cmake <client_building>`.
- ``libxkbcommon-dev``
- ``libwayland-bin``
- ``libwayland-dev``
- ``wayland-protocols``
- Disable with ``cmake -DENABLE_PIPEWIRE=no ..``
@@ -145,7 +146,7 @@ You can fetch these dependencies with the following command:
apt-get install binutils-dev cmake fonts-dejavu-core libfontconfig-dev \
gcc g++ pkg-config libegl-dev libgl-dev libgles-dev libspice-protocol-dev \
nettle-dev libx11-dev libxcursor-dev libxi-dev libxinerama-dev \
libxpresent-dev libxss-dev libxkbcommon-dev libwayland-dev \
libxpresent-dev libxss-dev libxkbcommon-dev libwayland-dev wayland-protocols \
libpipewire-0.3-dev libpulse-dev libsamplerate0-dev
You may omit some dependencies if you disable the feature which requires them

View File

@@ -49,7 +49,7 @@ getCalls() {
cat > "$tempdir/query" <<EOF
set output print
set bind-root false
m callExpr(callee(functionDecl(matchesName("::$query"), unless(isStatic())).bind("func")))
m callExpr(callee(functionDecl(matchesName("::$query")).bind("func")))
EOF
"${command[@]}" -exec "$CLANG_QUERY" -p "$BUILD_DIR/compile_commands.json" -f "$tempdir/query" {} + | \

View File

@@ -987,17 +987,11 @@ static bool d12_enumerateDevices(
DEBUG_INFO("Adapter matched, trying: %ls", adapterDesc.Description);
}
for (int n = 0; ; ++n, comRef_release(output))
for(
int n = 0;
IDXGIAdapter1_EnumOutputs(*adapter, n, output) != DXGI_ERROR_NOT_FOUND;
++n, comRef_release(output))
{
HRESULT hr = IDXGIAdapter1_EnumOutputs(*adapter, n, output);
if (FAILED(hr))
{
if (hr != DXGI_ERROR_NOT_FOUND)
DEBUG_WINERROR("Failed to IDXGIAdapter::EnumOutputs", hr);
break;
}
IDXGIOutput_GetDesc(*output, &outputDesc);
if (optOutput)

View File

@@ -1,4 +1,4 @@
/**
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
@@ -31,8 +31,7 @@ struct LGPipeMsg
{
SETCURSORPOS,
SETDISPLAYMODE,
GPUSTATUS,
RELOADSETTINGS
GPUSTATUS
}
type;
union

View File

@@ -45,14 +45,14 @@ static const struct LGMPQueueConfig POINTER_QUEUE_CONFIG =
static const UINT IDDCX_VERSION_1_10 = 0x1A00;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
static inline IDDCX_WIRE_BITS_PER_COMPONENT GetWireBitsPerComponent(bool hdr)
{
IDDCX_WIRE_BITS_PER_COMPONENT bits = {};
bits.Rgb = IDDCX_BITS_PER_COMPONENT_8;
if (hdr)
bits.Rgb = (IDDCX_BITS_PER_COMPONENT)(bits.Rgb |
IDDCX_BITS_PER_COMPONENT_10 | IDDCX_BITS_PER_COMPONENT_16);
bits.Rgb = (IDDCX_BITS_PER_COMPONENT)(bits.Rgb | IDDCX_BITS_PER_COMPONENT_10);
bits.YCbCr444 = IDDCX_BITS_PER_COMPONENT_NONE;
bits.YCbCr422 = IDDCX_BITS_PER_COMPONENT_NONE;
bits.YCbCr420 = IDDCX_BITS_PER_COMPONENT_NONE;
@@ -74,7 +74,8 @@ void CIndirectDeviceContext::QueryIddCxCapabilities()
m_iddCxVersion = ver.IddCxVersion;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
const bool hasIddCx110DDIs =
!!IDD_IS_FUNCTION_AVAILABLE(IddCxSwapChainReleaseAndAcquireBuffer2) &&
!!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorQueryHardwareCursor3) &&
@@ -125,7 +126,8 @@ void CIndirectDeviceContext::InitAdapter()
* driver will not work. This behaviour is not documented by Microsoft.
*/
caps.Flags = IDDCX_ADAPTER_FLAGS_USE_SMALLEST_MODE;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
if (CanUseIddCx110DDIs())
caps.Flags |= IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16;
#endif
@@ -186,7 +188,7 @@ void CIndirectDeviceContext::InitAdapter()
dxgiAdapter->Release();
if ((adapterDesc.VendorId == 0x1414 && adapterDesc.DeviceId == 0x008c) || // Microsoft Basic Render Driver
(adapterDesc.VendorId == 0x1b36 && adapterDesc.DeviceId == 0x000d) || // QXL
(adapterDesc.VendorId == 0x1b36 && adapterDesc.DeviceId == 0x000d) || // QXL
(adapterDesc.VendorId == 0x1234 && adapterDesc.DeviceId == 0x1111)) // QEMU Standard VGA
continue;
@@ -198,7 +200,7 @@ void CIndirectDeviceContext::InitAdapter()
factory->Release();
auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(m_adapter);
wrapper->context = this;
wrapper->context = this;
}
void CIndirectDeviceContext::FinishInit(UINT connectorIndex)
@@ -310,7 +312,7 @@ static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO & mode, DWORD
mode.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
mode.AdditionalSignalInfo.videoStandard = 255;
mode.vSyncFreq.Numerator = vsync;
mode.vSyncFreq.Denominator = 1;
mode.hSyncFreq.Numerator = vsync * height;
@@ -387,7 +389,8 @@ NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes(
}
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
NTSTATUS CIndirectDeviceContext::ParseMonitorDescription2(
const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs,
IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs)
@@ -443,7 +446,8 @@ bool CIndirectDeviceContext::UpdateMonitorModes()
if (!m_monitor)
return false;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
if (CanUseIddCx110DDIs())
{
IDDCX_TARGET_MODE2* modes = (IDDCX_TARGET_MODE2*)_malloca(
@@ -549,7 +553,7 @@ bool CIndirectDeviceContext::SetupLGMP(size_t alignSize)
return true;
m_alignSize = alignSize;
std::stringstream ss;
{
KVMFR kvmfr = {};
@@ -825,35 +829,6 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
++m_formatVer;
}
// Detect HDR metadata changes that require a format version bump
// so the client knows to re-apply the HDR image description.
if (srcFormat.hdr)
{
if (!m_lastHDRActive ||
memcmp(m_lastHDRDisplayPrimary, srcFormat.displayPrimary, sizeof(m_lastHDRDisplayPrimary)) != 0 ||
memcmp(m_lastHDRWhitePoint , srcFormat.whitePoint , sizeof(m_lastHDRWhitePoint )) != 0 ||
m_lastHDRMaxDisplayLuminance != srcFormat.maxDisplayLuminance ||
m_lastHDRMinDisplayLuminance != srcFormat.minDisplayLuminance ||
m_lastHDRMaxContentLightLevel != srcFormat.maxContentLightLevel ||
m_lastHDRMaxFrameAverageLightLevel != srcFormat.maxFrameAverageLightLevel)
{
++m_formatVer;
}
}
else if (m_lastHDRActive)
{
// HDR was turned off
++m_formatVer;
}
m_lastHDRActive = srcFormat.hdr;
memcpy(m_lastHDRDisplayPrimary, srcFormat.displayPrimary, sizeof(m_lastHDRDisplayPrimary));
memcpy(m_lastHDRWhitePoint , srcFormat.whitePoint , sizeof(m_lastHDRWhitePoint ));
m_lastHDRMaxDisplayLuminance = srcFormat.maxDisplayLuminance;
m_lastHDRMinDisplayLuminance = srcFormat.minDisplayLuminance;
m_lastHDRMaxContentLightLevel = srcFormat.maxContentLightLevel;
m_lastHDRMaxFrameAverageLightLevel = srcFormat.maxFrameAverageLightLevel;
if (++m_frameIndex == LGMP_Q_FRAME_LEN)
m_frameIndex = 0;
@@ -875,6 +850,9 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
(dstFormat.hdr ? FRAME_FLAG_HDR : 0) |
(dstFormat.hdrPQ ? FRAME_FLAG_HDR_PQ : 0);
if (dstFormat.format == FRAME_TYPE_RGBA16F)
flags |= FRAME_FLAG_HDR;
if (maxRows < dstFormat.desc.Height)
flags |= FRAME_FLAG_TRUNCATED;
@@ -892,18 +870,6 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
fi->flags = flags;
fi->rotation = FRAME_ROT_0;
fi->type = dstFormat.format;
// Populate HDR metadata if the frame is HDR
if (flags & FRAME_FLAG_HDR)
{
memcpy(fi->hdrDisplayPrimary, srcFormat.displayPrimary, sizeof(fi->hdrDisplayPrimary));
memcpy(fi->hdrWhitePoint , srcFormat.whitePoint , sizeof(fi->hdrWhitePoint));
fi->hdrMaxDisplayLuminance = srcFormat.maxDisplayLuminance;
fi->hdrMinDisplayLuminance = srcFormat.minDisplayLuminance;
fi->hdrMaxContentLightLevel = srcFormat.maxContentLightLevel;
fi->hdrMaxFrameAverageLightLevel = srcFormat.maxFrameAverageLightLevel;
}
fi->damageRectsCount = 0;
if (nbDirtyRects <= ARRAYSIZE(fi->damageRects))
{
@@ -965,7 +931,7 @@ void CIndirectDeviceContext::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, co
}
KVMFRCursor * cursor = (KVMFRCursor *)lgmpHostMemPtr(mem);
m_cursorVisible = info.IsCursorVisible;
uint32_t flags = 0;
@@ -1018,59 +984,6 @@ void CIndirectDeviceContext::SendCursor(const IDARG_OUT_QUERY_HWCURSOR& info, co
}
}
#ifdef HAS_IDDCX_110
void CIndirectDeviceContext::SetHDRActive(const struct IDDCX_HDR10_METADATA * hdrMeta)
{
AcquireSRWLockExclusive(&m_hdrLock);
if (!hdrMeta)
{
m_hdrActive = false;
ReleaseSRWLockExclusive(&m_hdrLock);
return;
}
m_hdrActive = true;
m_hdrDisplayPrimary[0][0] = hdrMeta->RedPrimary [0];
m_hdrDisplayPrimary[0][1] = hdrMeta->RedPrimary [1];
m_hdrDisplayPrimary[1][0] = hdrMeta->GreenPrimary[0];
m_hdrDisplayPrimary[1][1] = hdrMeta->GreenPrimary[1];
m_hdrDisplayPrimary[2][0] = hdrMeta->BluePrimary [0];
m_hdrDisplayPrimary[2][1] = hdrMeta->BluePrimary [1];
m_hdrWhitePoint [0] = hdrMeta->WhitePoint [0];
m_hdrWhitePoint [1] = hdrMeta->WhitePoint [1];
m_hdrMaxDisplayLuminance = hdrMeta->MaxMasteringLuminance;
m_hdrMinDisplayLuminance = hdrMeta->MinMasteringLuminance;
m_hdrMaxContentLightLevel = hdrMeta->MaxContentLightLevel;
m_hdrMaxFrameAverageLightLevel = hdrMeta->MaxFrameAverageLightLevel;
ReleaseSRWLockExclusive(&m_hdrLock);
}
#endif
bool CIndirectDeviceContext::GetHDRMetadata(D12FrameFormat & format) const
{
AcquireSRWLockShared(&m_hdrLock);
if (!m_hdrActive)
{
ReleaseSRWLockShared(&m_hdrLock);
return false;
}
memcpy(format.displayPrimary, m_hdrDisplayPrimary, sizeof(format.displayPrimary));
memcpy(format.whitePoint , m_hdrWhitePoint , sizeof(format.whitePoint ));
format.maxDisplayLuminance = m_hdrMaxDisplayLuminance;
format.minDisplayLuminance = m_hdrMinDisplayLuminance;
format.maxContentLightLevel = m_hdrMaxContentLightLevel;
format.maxFrameAverageLightLevel = m_hdrMaxFrameAverageLightLevel;
ReleaseSRWLockShared(&m_hdrLock);
return true;
}
void CIndirectDeviceContext::ResendCursor() const
{
PLGMPMemory mem = m_pointerShape;
@@ -1097,4 +1010,4 @@ void CIndirectDeviceContext::ResendCursor() const
DEBUG_ERROR("lgmpHostQueuePost Failed (Pointer): %s", lgmpStatusString(status));
break;
}
}
}

View File

@@ -35,15 +35,6 @@ extern "C" {
}
#include "common/KVMFR.h"
// IddCx 1.10 HDR/WCG types are only visible when the WDK targets
// (NTDDI >= 0x0A000005) *and* the build flags IDDCX_VERSION_MAJOR/MINOR are set to >= 1.10.
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) && \
NTDDI_VERSION >= 0x0A000005
#define HAS_IDDCX_110
#endif
#define MAX_POINTER_SIZE (sizeof(KVMFRCursor) + (512 * 512 * 4))
#define POINTER_SHAPE_BUFFERS 3
@@ -99,27 +90,6 @@ private:
UINT m_iddCxVersion = 0;
bool m_canProcessFP16 = false;
// HDR state from EvtIddCxMonitorSetDefaultHdrMetadata (IddCx 1.10+)
// Protected by m_hdrLock - accessed from both the IDD callback thread
// (SetHDRActive) and the swap-chain thread (PrepareFrameBuffer, GetHDRMetadata).
mutable SRWLOCK m_hdrLock = SRWLOCK_INIT;
bool m_hdrActive = false;
uint16_t m_hdrDisplayPrimary[3][2] = {};
uint16_t m_hdrWhitePoint[2] = {};
uint32_t m_hdrMaxDisplayLuminance = 0;
uint32_t m_hdrMinDisplayLuminance = 0;
uint32_t m_hdrMaxContentLightLevel = 0;
uint32_t m_hdrMaxFrameAverageLightLevel = 0;
// Previous HDR metadata used to detect changes for formatVer bumps
uint16_t m_lastHDRDisplayPrimary[3][2] = {};
uint16_t m_lastHDRWhitePoint[2] = {};
uint32_t m_lastHDRMaxDisplayLuminance = 0;
uint32_t m_lastHDRMinDisplayLuminance = 0;
uint32_t m_lastHDRMaxContentLightLevel = 0;
uint32_t m_lastHDRMaxFrameAverageLightLevel = 0;
bool m_lastHDRActive = false;
void QueryIddCxCapabilities();
bool CanUseIddCx110DDIs() const { return m_canProcessFP16; }
@@ -160,7 +130,8 @@ public:
NTSTATUS MonitorQueryTargetModes(
const IDARG_IN_QUERYTARGETMODES* inArgs, IDARG_OUT_QUERYTARGETMODES* outArgs);
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
NTSTATUS ParseMonitorDescription2(
const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs);
NTSTATUS MonitorQueryTargetModes2(
@@ -185,22 +156,6 @@ public:
void SendCursor(const IDARG_OUT_QUERY_HWCURSOR & info, const BYTE * data);
// Tracks HDR state from EvtIddCxMonitorSetDefaultHdrMetadata
void SetHDRActive(const struct IDDCX_HDR10_METADATA * hdrMeta);
// Returns true if the display is currently in HDR mode
bool IsHDRActive() const
{
AcquireSRWLockShared(&m_hdrLock);
bool result = m_hdrActive;
ReleaseSRWLockShared(&m_hdrLock);
return result;
}
// Copies current HDR metadata into the provided D12FrameFormat.
// Returns true if HDR is active and metadata was copied.
bool GetHDRMetadata(D12FrameFormat & format) const;
CIVSHMEM &GetIVSHMEM() { return m_ivshmem; }
};
@@ -215,4 +170,4 @@ struct CIndirectDeviceContextWrapper
}
};
WDF_DECLARE_CONTEXT_TYPE(CIndirectDeviceContextWrapper);
WDF_DECLARE_CONTEXT_TYPE(CIndirectDeviceContextWrapper);

View File

@@ -1,4 +1,4 @@
/**
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
@@ -29,7 +29,7 @@ bool CPipeServer::Init()
m_pipe.Attach(CreateNamedPipeA(
LG_PIPE_NAME,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1,
1024,
@@ -43,13 +43,6 @@ bool CPipeServer::Init()
return false;
}
m_signal.Attach(CreateEvent(NULL, TRUE, FALSE, NULL));
if (!m_signal.IsValid())
{
DEBUG_ERROR_HR(GetLastError(), "Failed to create pipe signal event");
return false;
}
m_running = true;
m_thread.Attach(CreateThread(
NULL,
@@ -73,11 +66,10 @@ void CPipeServer::_DeInit()
{
m_running = false;
m_connected = false;
if (m_signal.IsValid())
SetEvent(m_signal.Get());
if (m_thread.IsValid())
{
CancelSynchronousIo(m_thread.Get());
WaitForSingleObject(m_thread.Get(), INFINITE);
m_thread.Close();
}
@@ -87,8 +79,6 @@ void CPipeServer::_DeInit()
FlushFileBuffers(m_pipe.Get());
m_pipe.Close();
}
m_signal.Close();
}
void CPipeServer::DeInit()
@@ -101,47 +91,24 @@ void CPipeServer::DeInit()
void CPipeServer::Thread()
{
DEBUG_TRACE("Pipe thread started");
HandleT<EventTraits> ioEvent(CreateEvent(NULL, TRUE, FALSE, NULL));
if (!ioEvent.IsValid())
{
DEBUG_ERROR_HR(GetLastError(), "Can't create event for overlapped I/O!");
WaitForSingleObject(m_signal.Get(), 5000);
return;
}
while(m_running)
{
m_connected = false;
OVERLAPPED overlapped = { 0 };
overlapped.hEvent = ioEvent.Get();
if (!ConnectNamedPipe(m_pipe.Get(), &overlapped))
bool result = ConnectNamedPipe(m_pipe.Get(), NULL);
DWORD err = GetLastError();
if (!result && err != ERROR_PIPE_CONNECTED)
{
DWORD dwError = GetLastError();
switch (dwError) {
case ERROR_PIPE_CONNECTED:
// if graceful shutdown
if ((err == ERROR_OPERATION_ABORTED && !m_running) ||
err == ERROR_NO_DATA)
break;
case ERROR_IO_PENDING:
{
HANDLE hWait[] = { ioEvent.Get(), m_signal.Get() };
switch (WaitForMultipleObjects(2, hWait, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
DEBUG_INFO("Connect interrupted by signal");
CancelIo(m_pipe.Get());
WaitForSingleObject(ioEvent.Get(), INFINITE);
continue;
}
break;
}
default:
DEBUG_ERROR_HR(dwError, "Error connecting to the named pipe");
goto end;
}
// if timeout
if (err == ERROR_SEM_TIMEOUT)
continue;
DEBUG_FATAL_HR(err, "Error connecting to the named pipe");
break;
}
DEBUG_TRACE("Client connected");
@@ -154,65 +121,14 @@ void CPipeServer::Thread()
while (m_running && m_connected)
{
LGPipeMsg msg;
if (!ReadFile(m_pipe.Get(), &msg, sizeof(msg), NULL, &overlapped))
{
DWORD dwError = GetLastError();
if (dwError != ERROR_IO_PENDING)
{
DEBUG_ERROR_HR(dwError, "ReadFile Failed");
break;
}
HANDLE hWait[] = { ioEvent.Get(), m_signal.Get() };
switch (WaitForMultipleObjects(2, hWait, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
DEBUG_INFO("I/O interrupted by signal");
CancelIo(m_pipe.Get());
WaitForSingleObject(ioEvent.Get(), INFINITE);
continue;
}
}
DWORD bytesRead;
GetOverlappedResult(m_pipe.Get(), &overlapped, &bytesRead, TRUE);
if (bytesRead != sizeof(msg))
{
DEBUG_ERROR("Corrupted data, expected %lld bytes, read %lld bytes", sizeof msg, bytesRead);
break;
}
if (msg.size != sizeof(msg))
{
DEBUG_ERROR("Corrupted data, expected %lld bytes, actual message size: %lld bytes", sizeof msg, msg.size);
break;
}
switch (msg.type)
{
case LGPipeMsg::RELOADSETTINGS:
HandleReloadSettings();
break;
default:
DEBUG_ERROR("Unknown message type %d", msg.type);
break;
}
//TODO: Read messages from the client
Sleep(1000);
}
DEBUG_TRACE("Client disconnected");
DisconnectNamedPipe(m_pipe.Get());
if (m_running)
ResetEvent(m_signal.Get());
}
end:
m_running = false;
m_connected = false;
DEBUG_TRACE("Pipe thread shutdown");
@@ -234,7 +150,6 @@ void CPipeServer::WriteMsg(const LGPipeMsg & msg)
{
DEBUG_WARN_HR(err, "Client disconnected, failed to write");
m_connected = false;
SetEvent(m_signal.Get());
return;
}
@@ -245,11 +160,6 @@ void CPipeServer::WriteMsg(const LGPipeMsg & msg)
FlushFileBuffers(m_pipe.Get());
}
void CPipeServer::HandleReloadSettings()
{
DEBUG_INFO("TODO: reload settings");
}
void CPipeServer::SetCursorPos(uint32_t x, uint32_t y)
{
// do not send cursor messages if we are not connected or they will end up queued

View File

@@ -1,4 +1,4 @@
/**
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
@@ -35,9 +35,8 @@ using namespace Microsoft::WRL::Wrappers::HandleTraits;
class CPipeServer
{
private:
HandleT<HANDLETraits> m_pipe;
HandleT<HANDLENullTraits> m_pipe;
HandleT<HANDLENullTraits> m_thread;
HandleT<EventTraits> m_signal;
std::vector<LGPipeMsg> m_queue;
bool m_running = false;
@@ -50,8 +49,6 @@ class CPipeServer
void WriteMsg(const LGPipeMsg & msg);
void HandleReloadSettings();
public:
~CPipeServer() { DeInit(); }

View File

@@ -1,4 +1,4 @@
/**
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
@@ -32,60 +32,6 @@ int CPlatformInfo::m_cores = 0;
int CPlatformInfo::m_procs = 0;
int CPlatformInfo::m_sockets = 0;
typedef PWSTR (WINAPI *PFN_BRANDING_FORMAT_STRING)(__in PCWSTR pstrFormat);
inline bool brandingVersionString(std::string &output)
{
HMODULE hWinBrand = LoadLibraryExA("winbrand.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!hWinBrand)
return false;
PFN_BRANDING_FORMAT_STRING BrandingFormatString =
(PFN_BRANDING_FORMAT_STRING) GetProcAddress(hWinBrand, "BrandingFormatString");
bool succeeded = false;
if (BrandingFormatString)
{
PWSTR pwstrOSName = BrandingFormatString(L"%WINDOWS_LONG%");
if (pwstrOSName)
{
int cbSize = WideCharToMultiByte(CP_UTF8, 0, pwstrOSName, -1, nullptr, 0, nullptr, nullptr);
output.resize(cbSize - 1);
if (WideCharToMultiByte(CP_UTF8, 0, pwstrOSName, -1, &output[0], cbSize, nullptr, nullptr))
succeeded = true;
GlobalFree((HGLOBAL)pwstrOSName);
}
}
FreeLibrary(hWinBrand);
return succeeded;
}
inline bool registryVersionString(std::string &output)
{
DWORD bufferSize = 0;
LSTATUS status = RegGetValueA(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName",
RRF_RT_REG_SZ, nullptr, nullptr, &bufferSize);
if (status == ERROR_SUCCESS)
{
output.resize(bufferSize - 1);
status = RegGetValueA(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName",
RRF_RT_REG_SZ, nullptr, &output[0], &bufferSize);
if (status == ERROR_SUCCESS)
return true;
}
return false;
}
void CPlatformInfo::Init()
{
SYSTEM_INFO si;
@@ -100,7 +46,26 @@ void CPlatformInfo::Init()
GetVersionExA(&osvi);
#pragma warning(pop)
if (!brandingVersionString(m_productName) && !registryVersionString(m_productName))
DWORD bufferSize = 0;
LSTATUS status = RegGetValueA(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName",
RRF_RT_REG_SZ, nullptr, nullptr, &bufferSize);
if (status == ERROR_SUCCESS)
{
m_productName.resize(bufferSize);
status = RegGetValueA(HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows NT\\CurrentVersion", "ProductName",
RRF_RT_REG_SZ, nullptr, &m_productName[0], &bufferSize);
if (status != ERROR_SUCCESS)
{
m_productName = "Unknown";
DEBUG_ERROR("Failed to read the ProductName");
}
else
m_productName.resize(bufferSize - 1); // remove the double null termination
}
else
{
m_productName = "Windows " +
std::to_string(osvi.dwMajorVersion) + "." +

View File

@@ -41,19 +41,6 @@ struct D12FrameFormat
FrameType format = FRAME_TYPE_INVALID;
bool hdr = false;
bool hdrPQ = false;
// HDR static metadata (SMPTE ST 2086)
// Display color primaries in 0.00002 units (xy coordinates)
uint16_t displayPrimary[3][2];
// White point in 0.00002 units
uint16_t whitePoint[2];
// Max display luminance in 0.0001 cd/m² units
uint32_t maxDisplayLuminance;
// Min display luminance in 0.0001 cd/m² units
uint32_t minDisplayLuminance;
// MaxCLL and MaxFALL in cd/m²
uint32_t maxContentLightLevel;
uint32_t maxFrameAverageLightLevel;
};
class CPostProcessEffect

View File

@@ -145,7 +145,8 @@ void CSwapChainProcessor::SwapChainThreadCore()
UINT dirtyRectCount = 0;
ComPtr<IDXGIResource> surface;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
if (m_devContext->CanProcessFP16())
{
IDARG_IN_RELEASEANDACQUIREBUFFER2 acquireIn = {};
@@ -365,59 +366,8 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
srcFormat.width = (unsigned)srcDesc.Width;
srcFormat.height = srcDesc.Height;
srcFormat.format = GetFrameType(srcDesc.Format);
// Only HDR-capable formats can carry HDR content.
// 8-bit formats (BGRA, RGBA) cannot represent HDR,
// even if IsHDRActive() is momentarily stale during mode switches.
if (srcDesc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT &&
srcDesc.Format != DXGI_FORMAT_R10G10B10A2_UNORM)
{
srcFormat.hdr = false;
srcFormat.hdrPQ = false;
}
else if (srcDesc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT)
{
// FP16 is HDR content (scRGB / linear, not PQ-curve).
// FP16 always carries HDR color data regardless of OS HDR mode,
// but metadata (primaries, luminances) may be unavailable.
srcFormat.hdr = true;
srcFormat.hdrPQ = false;
if (!m_devContext->GetHDRMetadata(srcFormat))
{
// No HDR metadata from the OS; provide reasonable defaults
// so downstream consumers have valid primaries and luminances.
// BT.709/sRGB primaries (in 0.00002 units):
srcFormat.displayPrimary[0][0] = 13250; // Rx
srcFormat.displayPrimary[0][1] = 34500; // Ry
srcFormat.displayPrimary[1][0] = 7500; // Gx
srcFormat.displayPrimary[1][1] = 30000; // Gy
srcFormat.displayPrimary[2][0] = 34000; // Bx
srcFormat.displayPrimary[2][1] = 16000; // By
// D65 white point (in 0.00002 units):
srcFormat.whitePoint[0] = 15635;
srcFormat.whitePoint[1] = 16450;
// 80 cd/m² display, 0.005 cd/m² black (in 0.0001 cd/m² units):
srcFormat.maxDisplayLuminance = 800000;
srcFormat.minDisplayLuminance = 50;
// Content light levels unknown:
srcFormat.maxContentLightLevel = 0;
srcFormat.maxFrameAverageLightLevel = 0;
}
}
else if (m_devContext->CanProcessFP16() && m_devContext->IsHDRActive())
{
// Non-FP16 format (e.g., RGBA10) with OS HDR mode active.
// Windows applies the PQ (ST.2084) transfer function for non-FP16 HDR.
srcFormat.hdr = true;
srcFormat.hdrPQ = true;
// Load HDR metadata; if none is available the frame is not HDR.
if (!m_devContext->GetHDRMetadata(srcFormat))
{
srcFormat.hdr = false;
srcFormat.hdrPQ = false;
}
}
srcFormat.hdr = srcDesc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT;
srcFormat.hdrPQ = false;
bool postProcessFormatChanged = false;
if (!m_postProcessor.Configure(srcFormat, &postProcessFormatChanged))
@@ -561,7 +511,8 @@ bool CSwapChainProcessor::QueryHWCursor()
IDARG_OUT_QUERY_HWCURSOR out = {};
NTSTATUS status;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
if (m_devContext->CanProcessFP16())
{
IDARG_OUT_QUERY_HWCURSOR3 out3 = {};
@@ -637,4 +588,4 @@ void CSwapChainProcessor::CursorThread()
return;
}
}
}
}

View File

@@ -40,7 +40,8 @@ static const UINT IDDCX_VERSION_1_10 = 0x1A00;
static bool LGIddCanUseIddCx110DDIs(UINT iddCxVersion)
{
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
return iddCxVersion >= IDDCX_VERSION_1_10 &&
!!IDD_IS_FUNCTION_AVAILABLE(IddCxSwapChainReleaseAndAcquireBuffer2) &&
!!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorQueryHardwareCursor3) &&
@@ -60,7 +61,7 @@ static bool LGIddCanUseIddCx110DDIs(UINT iddCxVersion)
NTSTATUS LGIddDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previousState)
{
UNREFERENCED_PARAMETER(previousState);
auto * wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(device);
wrapper->context->InitAdapter();
@@ -91,7 +92,7 @@ static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO & mode, DWORD
mode.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
mode.AdditionalSignalInfo.videoStandard = 255;
mode.vSyncFreq.Numerator = vsync;
mode.vSyncFreq.Denominator = 1;
mode.hSyncFreq.Numerator = vsync * height;
@@ -126,7 +127,8 @@ NTSTATUS LGIddMonitorQueryTargetModes(IDDCX_MONITOR monitor, const IDARG_IN_QUER
}
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
NTSTATUS LGIddParseMonitorDescription2(const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs,
IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs)
{
@@ -163,11 +165,8 @@ NTSTATUS LGIddAdapterCommitModes2(IDDCX_ADAPTER adapter, const IDARG_IN_COMMITMO
NTSTATUS LGIddMonitorSetDefaultHdrMetadata(IDDCX_MONITOR monitor,
const IDARG_IN_MONITOR_SET_DEFAULT_HDR_METADATA* inArgs)
{
auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor);
auto* ctx = wrapper->context->GetDeviceContext();
ctx->SetHDRActive(inArgs->Data.pHdr10);
UNREFERENCED_PARAMETER(monitor);
UNREFERENCED_PARAMETER(inArgs);
return STATUS_SUCCESS;
}
@@ -229,7 +228,8 @@ NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit)
config.EvtIddCxMonitorAssignSwapChain = LGIddMonitorAssignSwapChain;
config.EvtIddCxMonitorUnassignSwapChain = LGIddMonitorUnassignSwapChain;
#ifdef HAS_IDDCX_110
#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \
(IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10))
if (hasIddCx110DDIs)
{
config.EvtIddCxParseMonitorDescription2 = LGIddParseMonitorDescription2;

View File

@@ -36,24 +36,14 @@ bool CHDR16to10Effect::Init(const ComPtr<ID3D12Device3>& device)
const char * shader =
"cbuffer Constants : register(b0)\n"
"{\n"
" float ReferenceWhiteNits;\n"
" float SDRWhiteLevel;\n"
"};\n"
"Texture2D<float4> src : register(t0);\n"
"RWTexture2D<float4> dst : register(u0);\n"
"static const float PQ_m1 = 0.1593017578125;\n"
"static const float PQ_m2 = 78.84375;\n"
"static const float PQ_c1 = 0.8359375;\n"
"static const float PQ_c2 = 18.8515625;\n"
"static const float PQ_c3 = 18.6875;\n"
"[numthreads(" POST_PROCESS_THREADS_STR ", " POST_PROCESS_THREADS_STR ", 1)]\n"
"void main(uint3 dt : SV_DispatchThreadID)\n"
"{\n"
" float3 linearValue = src[dt.xy].rgb * ReferenceWhiteNits;\n"
" // scRGB to PQ (ST.2084)\n"
" float3 Y = linearValue / 10000.0;\n"
" float3 Ym1 = pow(max(Y, 0.0), PQ_m1);\n"
" float3 pq = pow((PQ_c1 + PQ_c2 * Ym1) / (1.0 + PQ_c3 * Ym1), PQ_m2);\n"
" dst[dt.xy] = float4(pq, src[dt.xy].a);\n"
" dst[dt.xy] = float4(src[dt.xy].rgb * SDRWhiteLevel, src[dt.xy].a);\n"
"}\n";
if (!InitCompute(device, ranges, ARRAYSIZE(ranges), nullptr, 0, shader))
@@ -109,20 +99,10 @@ PostProcessStatus CHDR16to10Effect::SetFormat(
m_threadsX = ((unsigned)desc.Width + (Threads - 1)) / Threads;
m_threadsY = ((unsigned)desc.Height + (Threads - 1)) / Threads;
dst.desc = desc;
dst.desc = desc;
dst.format = FRAME_TYPE_RGBA10;
dst.hdr = true;
dst.hdrPQ = true;
// Explicitly propagate HDR static metadata so it survives post-processing.
// Do not rely on the caller's copy semantics in CPostProcessor::Configure().
memcpy(dst.displayPrimary, src.displayPrimary, sizeof(dst.displayPrimary));
memcpy(dst.whitePoint , src.whitePoint , sizeof(dst.whitePoint ));
dst.maxDisplayLuminance = src.maxDisplayLuminance;
dst.minDisplayLuminance = src.minDisplayLuminance;
dst.maxContentLightLevel = src.maxContentLightLevel;
dst.maxFrameAverageLightLevel = src.maxFrameAverageLightLevel;
dst.hdr = true;
dst.hdrPQ = false;
return PostProcessStatus::SUCCESS;
}

View File

@@ -18,8 +18,8 @@ class CHDR16to10Effect : public CComputeEffect
private:
struct Consts
{
float ReferenceWhiteNits; // scRGB reference white in nits (typically 80)
} m_consts = { 80.0f };
float SDRWhiteLevel;
} m_consts = { 1.0f };
ComPtr<ID3D12Resource> m_constBuffer;
public:

View File

@@ -35,6 +35,7 @@ bool CConfigWindow::registerClass()
{
WNDCLASSEX wx = {};
populateWindowClass(wx);
wx.hIconSm = wx.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wx.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wx.lpszClassName = L"LookingGlassIddConfig";
@@ -290,9 +291,7 @@ LRESULT CConfigWindow::onCommand(WORD id, WORD code, HWND hwnd)
m_modeBox->setSel(updateModeList(index));
LRESULT result = m_settings.setModes(*m_modes);
if (result == ERROR_SUCCESS)
sendSettingChange();
else
if (result != ERROR_SUCCESS)
DEBUG_ERROR_HR((HRESULT) result, "Failed to save modes");
}
else if (m_modeDelete && hwnd == *m_modeDelete && code == BN_CLICKED && m_modes)
@@ -305,27 +304,20 @@ LRESULT CConfigWindow::onCommand(WORD id, WORD code, HWND hwnd)
m_modeBox->clear();
m_modes->erase(m_modes->begin() + index);
LRESULT result = m_settings.setModes(*m_modes);
if (result != ERROR_SUCCESS)
DEBUG_ERROR_HR((HRESULT) result, "Failed to save modes");
updateModeList();
onModeListSelectChange();
LRESULT result = m_settings.setModes(*m_modes);
if (result == ERROR_SUCCESS)
sendSettingChange();
else
DEBUG_ERROR_HR((HRESULT) result, "Failed to save modes");
}
else if (m_modeReset && hwnd == *m_modeReset && code == BN_CLICKED && m_modes)
{
*m_modes = m_settings.getDefaultModes();
m_settings.setModes(*m_modes);
m_modeBox->clear();
updateModeList();
onModeListSelectChange();
LRESULT result = m_settings.setModes(*m_modes);
if (result == ERROR_SUCCESS)
sendSettingChange();
else
DEBUG_ERROR_HR((HRESULT)result, "Failed to save modes");
}
else if (m_defRefresh && hwnd == *m_defRefresh && code == EN_CHANGE && m_defaultRefresh)
{
@@ -340,11 +332,8 @@ LRESULT CConfigWindow::onCommand(WORD id, WORD code, HWND hwnd)
}
m_defaultRefresh = value;
LRESULT result = m_settings.setDefaultRefresh(value);
if (result == ERROR_SUCCESS)
sendSettingChange();
else
if (result != ERROR_SUCCESS)
DEBUG_ERROR_HR((HRESULT)result, "Failed to default refresh");
}
else if (m_prefNoGPU && hwnd == *m_prefNoGPU && code == BN_CLICKED && m_noGPU)

View File

@@ -64,8 +64,6 @@ class CConfigWindow : public CWindow
std::unique_ptr<CCheckbox> m_prefNoGPU;
std::function<void()> m_onDestroy;
std::function<void()> m_onSettingChange;
double m_scale;
Microsoft::WRL::Wrappers::HandleT<FontTraits> m_font;
CRegistrySettings m_settings;
@@ -77,7 +75,6 @@ class CConfigWindow : public CWindow
void updateFont();
int updateModeList(int wanted = -1);
void onModeListSelectChange();
void sendSettingChange() { if (m_onSettingChange) m_onSettingChange(); }
virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
virtual LRESULT onCreate() override;
@@ -90,5 +87,4 @@ public:
static bool registerClass();
void onDestroy(std::function<void()> func) { m_onDestroy = std::move(func); }
void onSettingChange(std::function<void()> func) { m_onSettingChange = std::move(func); }
};

View File

@@ -20,7 +20,6 @@
#include "CNotifyWindow.h"
#include "CConfigWindow.h"
#include "Resources.h"
#include <CDebug.h>
#include <windowsx.h>
#include <strsafe.h>
@@ -49,8 +48,8 @@ bool CNotifyWindow::registerClass()
return s_atom;
}
CNotifyWindow::CNotifyWindow() : m_iconData({ 0 }), m_iconRegistered(false),
m_menu(CreatePopupMenu()), closeRequested(false)
CNotifyWindow::CNotifyWindow() : m_iconData({ 0 }), m_menu(CreatePopupMenu()),
closeRequested(false)
{
CreateWindowEx(0, MAKEINTATOM(s_atom), NULL,
0, 0, 0, 0, 0, NULL, NULL, hInstance, this);
@@ -83,7 +82,7 @@ LRESULT CNotifyWindow::handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
return 0;
case WM_NO_GPU:
handleGPUNotification((bool)wParam);
handleNoGPUNotification();
return 0;
default:
@@ -141,8 +140,6 @@ LRESULT CNotifyWindow::onNotifyIcon(UINT uEvent, WORD wIconId, int x, int y)
m_config->onDestroy([this]() {
PostMessage(m_hwnd, WM_CLEAN_UP_CONFIG, 0, 0);
});
if (m_onSettingChange)
m_config->onSettingChange(m_onSettingChange);
ShowWindow(*m_config, SW_NORMAL);
break;
}
@@ -155,9 +152,9 @@ void CNotifyWindow::registerIcon()
{
m_iconData.cbSize = sizeof m_iconData;
m_iconData.hWnd = m_hwnd;
m_iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_SHOWTIP;
m_iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
m_iconData.uCallbackMessage = WM_NOTIFY_ICON;
m_iconData.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_MAIN_ICON));
m_iconData.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
m_iconData.uVersion = NOTIFYICON_VERSION_4;
StringCbCopy(m_iconData.szTip, sizeof m_iconData.szTip, L"Looking Glass (IDD)");
@@ -167,45 +164,17 @@ void CNotifyWindow::registerIcon()
return;
}
m_iconRegistered = true;
if (!Shell_NotifyIcon(NIM_SETVERSION, &m_iconData))
DEBUG_ERROR_HR(GetLastError(), "Shell_NotifyIcon(NIM_SETVERSION)");
if (m_gpuQueue)
{
handleGPUNotification(*m_gpuQueue);
m_gpuQueue.reset();
}
}
void CNotifyWindow::setGPU(bool hasGPU)
void CNotifyWindow::noGPUNotification()
{
if (m_iconRegistered)
PostMessage(m_hwnd, WM_NO_GPU, hasGPU, 0);
else
m_gpuQueue.emplace(hasGPU);
PostMessage(m_hwnd, WM_NO_GPU, 0, 0);
}
void CNotifyWindow::handleGPUNotification(bool hasGPU)
void CNotifyWindow::handleNoGPUNotification()
{
StringCbCopy(m_iconData.szTip, sizeof m_iconData.szTip, hasGPU ?
L"Looking Glass (IDD) with GPU acceleration" :
L"Looking Glass (IDD) with software rendering");
if (hasGPU)
m_iconData.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_GPU_ICON));
else
m_iconData.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_NO_GPU_ICON));
if (!Shell_NotifyIcon(NIM_MODIFY, &m_iconData))
{
DEBUG_ERROR_HR(GetLastError(), "Shell_NotifyIcon(NIM_ADD)");
return;
}
if (hasGPU)
return;
CRegistrySettings settings;
LSTATUS error = settings.open();
if (error != ERROR_SUCCESS)
@@ -218,7 +187,7 @@ void CNotifyWindow::handleGPUNotification(bool hasGPU)
NOTIFYICONDATA nid;
memcpy(&nid, &m_iconData, sizeof nid);
nid.uFlags = NIF_INFO | NIF_SHOWTIP;
nid.uFlags = NIF_INFO;
nid.dwInfoFlags = NIIF_WARNING;
StringCbCopy(nid.szInfoTitle, sizeof nid.szInfoTitle, L"No GPU found!");
StringCbCopy(nid.szInfo, sizeof nid.szInfo,

View File

@@ -20,9 +20,7 @@
#pragma once
#include "CWindow.h"
#include <functional>
#include <memory>
#include <optional>
class CConfigWindow;
@@ -32,17 +30,13 @@ class CNotifyWindow : public CWindow
static ATOM s_atom;
NOTIFYICONDATA m_iconData;
bool m_iconRegistered;
std::optional<bool> m_gpuQueue;
HMENU m_menu;
bool closeRequested;
std::unique_ptr<CConfigWindow> m_config;
std::function<void()> m_onSettingChange;
LRESULT onNotifyIcon(UINT uEvent, WORD wIconId, int x, int y);
void registerIcon();
void handleGPUNotification(bool hasGPU);
void handleNoGPUNotification();
virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
virtual LRESULT onCreate() override;
@@ -68,10 +62,8 @@ public:
static bool registerClass();
void setGPU(bool hasGPU);
void noGPUNotification();
HWND hwndDialog();
void close();
void onSettingChange(std::function<void()> func) { m_onSettingChange = std::move(func); }
};

View File

@@ -170,17 +170,6 @@ void CPipeClient::WriteMsg(const LGPipeMsg& msg)
FlushFileBuffers(m_pipe.Get());
}
void CPipeClient::ReloadSettings()
{
if (!m_connected)
return;
LGPipeMsg msg;
msg.size = sizeof(msg);
msg.type = LGPipeMsg::RELOADSETTINGS;
WriteMsg(msg);
}
void CPipeClient::Thread()
{
DEBUG_INFO("Pipe thread started");
@@ -319,5 +308,6 @@ void CPipeClient::HandleSetDisplayMode(const LGPipeMsg& msg)
void CPipeClient::HandleGPUStatus(const LGPipeMsg& msg)
{
CNotifyWindow::instance().setGPU(!msg.gpuStatus.software);
if (msg.gpuStatus.software)
CNotifyWindow::instance().noGPUNotification();
}

View File

@@ -59,8 +59,6 @@ public:
bool Init();
void DeInit();
bool IsRunning() { return m_running; }
void ReloadSettings();
};
extern CPipeClient g_pipe;

View File

@@ -22,7 +22,6 @@
#include <windowsx.h>
#include <strsafe.h>
#include <CDebug.h>
#include "Resources.h"
HINSTANCE CWindow::hInstance = (HINSTANCE)GetModuleHandle(NULL);
@@ -31,8 +30,8 @@ void CWindow::populateWindowClass(WNDCLASSEX &wx)
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = wndProc;
wx.hInstance = hInstance;
wx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(ID_MAIN_ICON));
wx.hIconSm = wx.hIcon;
wx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wx.hCursor = LoadCursor(NULL, IDC_ARROW);
wx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@@ -91,8 +91,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
</PostBuildEvent>
<Manifest />
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
<InputResourceManifests>$(ProjectDir)HighDPI.manifest</InputResourceManifests>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -119,8 +118,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
</PostBuildEvent>
<Manifest />
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
<InputResourceManifests>$(ProjectDir)HighDPI.manifest</InputResourceManifests>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -146,8 +144,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
</PostBuildEvent>
<Manifest />
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
<InputResourceManifests>$(ProjectDir)HighDPI.manifest</InputResourceManifests>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -177,8 +174,7 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
</PostBuildEvent>
<Manifest />
<Manifest>
<EnableDpiAwareness>false</EnableDpiAwareness>
<InputResourceManifests>$(ProjectDir)HighDPI.manifest</InputResourceManifests>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
@@ -211,7 +207,6 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
<ClInclude Include="CRegistrySettings.h" />
<ClInclude Include="CStaticWidget.h" />
<ClInclude Include="CWidget.h" />
<ClInclude Include="Resources.h" />
<ClInclude Include="UIHelpers.h" />
<ClInclude Include="CWindow.h" />
</ItemGroup>
@@ -221,9 +216,6 @@ copy /Y "$(ProjectDir)VERSION" "$(SolutionDir)$(Platform)\$(Configuration)\LGIdd
<ItemGroup>
<ResourceCompile Include="resource.rc" />
</ItemGroup>
<ItemGroup>
<Manifest Include="HighDPI.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
<Target Name="GenerateVersionInfo" BeforeTargets="ClCompile">

View File

@@ -100,9 +100,6 @@
<ClInclude Include="CCheckbox.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Resources.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@@ -112,7 +109,4 @@
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="HighDPI.manifest" />
</ItemGroup>
</Project>
</Project>

View File

@@ -1,25 +0,0 @@
/**
* Looking Glass
* Copyright © 2017-2026 The Looking Glass Authors
* https://looking-glass.io
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc., 59
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#pragma once
#define ID_MAIN_ICON 1
#define ID_GPU_ICON 2
#define ID_NO_GPU_ICON 3

View File

@@ -120,10 +120,6 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
if (!g_pipe.Init())
return EXIT_FAILURE;
window.onSettingChange([]() {
g_pipe.ReloadSettings();
});
HANDLE hWait;
if (!RegisterWaitForSingleObject(&hWait, hParent.Get(), DestroyNotifyWindow, &window, INFINITE, WT_EXECUTEONLYONCE))
DEBUG_ERROR_HR(GetLastError(), "Failed to RegisterWaitForSingleObject");

View File

@@ -22,11 +22,8 @@
#include "winuser.h"
#include "winver.h"
#include "VersionInfo.h"
#include "Resources.h"
ID_MAIN_ICON ICON "../../resources/icon.ico"
ID_GPU_ICON ICON "../../resources/icon-gpu.ico"
ID_NO_GPU_ICON ICON "../../resources/icon-nogpu.ico"
IDI_APPLICATION ICON "../../resources/icon.ico"
#define STRINGIFY2(s) L#s
#define STRINGIFY(s) STRINGIFY2(s)

View File

@@ -96,7 +96,6 @@ typedef struct
uint32_t linesize;
bool hideMouse;
bool hdr;
#if LIBOBS_API_MAJOR_VER >= 27
bool dmabuf;
bool dmabufTested;
@@ -491,31 +490,15 @@ static void lgUpdate(void * data, obs_data_t * settings)
uint32_t udataSize;
KVMFR * udata;
LGMP_STATUS status;
if ((status = lgmpClientInit(this->shmDev.mem, this->shmDev.size,
&this->lgmp)) != LGMP_OK)
{
printf("lgmpClientInit: %s\n", lgmpStatusString(status));
if (lgmpClientInit(this->shmDev.mem, this->shmDev.size, &this->lgmp)
!= LGMP_OK)
return;
}
usleep(200000);
uint32_t remoteVersion;
if ((status = lgmpClientSessionInit(this->lgmp, &udataSize,
(uint8_t **)&udata, NULL, &remoteVersion)) != LGMP_OK)
{
printf("lgmpClientSessionInit: %s", lgmpStatusString(status));
if (status == LGMP_ERR_INVALID_VERSION)
{
printf("The host application is not compatible with this client\n");
printf("Expected LGMP version %u but got %u\n",
LGMP_PROTOCOL_VERSION, remoteVersion);
printf("This is not a Looking Glass error, do not report this");
}
printf("\n");
if (lgmpClientSessionInit(this->lgmp, &udataSize, (uint8_t **)&udata, NULL)
!= LGMP_OK)
return;
}
if (udataSize < sizeof(KVMFR) ||
memcmp(udata->magic, KVMFR_MAGIC, sizeof(udata->magic)) != 0 ||
@@ -620,7 +603,6 @@ static void lgFormatInit(LGPlugin * this, const KVMFRFrame * frame,
this->dataWidth = frame->dataWidth;
this->unpack = false;
this->hdr = frame->flags & FRAME_FLAG_HDR;
this->bpp = 4;
switch(this->type)
@@ -645,7 +627,7 @@ static void lgFormatInit(LGPlugin * this, const KVMFRFrame * frame,
this->format = GS_R10G10B10A2;
this->drmFormat = DRM_FORMAT_BGRA1010102;
#if LIBOBS_API_MAJOR_VER >= 28
this->colorSpace = this->hdr ? GS_CS_709_SCRGB : GS_CS_SRGB;
this->colorSpace = GS_CS_709_SCRGB;
#endif
break;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB