Files
AnyPS5/core/libs/prx/libSceVideoOut/src/HostHdrProbe.cpp
T
Gjon Gojcevic 4e27d8d753 fix(videoout): keep the output SDR on hosts without a monitor HDR report
A Vulkan surface can offer HDR10 formats while the display is not in
HDR (KDE Wayland with RADV lists them with the output's HDR disabled),
so on hosts other than Windows the probe now reports an SDR monitor and
HDR output stays off until an output-state signal exists. A probe test
checks that a window without a Windows monitor report reads as SDR with
an HDR10 surface.

The HDR10 present test now also changes the monitor's luminance while
presenting HDR10, and the presenter logs the HDR metadata it sets.

AI-assisted: yes
2026-10-14 08:55:18 -04:00

89 lines
3.1 KiB
C++

#include "prx/libSceVideoOut/include/HostHdrProbe.hpp"
#include "prx/libSceAgcDriver/Execution/include/HostHdr.hpp"
#include <stdexcept>
#ifdef _WIN32
#include "SDL_syswm.h"
#include <windows.h>
#include <dxgi1_6.h>
#endif
namespace {
#ifdef _WIN32
template<typename TInterface>
void releaseCom(TInterface*& object) noexcept {
if (object != nullptr) object->Release();
object = nullptr;
}
AgcDriver::HostDisplayHdr describeMonitor(IDXGIFactory1* factory, HMONITOR monitor) {
for (UINT adapterIndex = 0;; ++adapterIndex) {
IDXGIAdapter1* adapter = nullptr;
if (FAILED(factory->EnumAdapters1(adapterIndex, &adapter))) return {};
for (UINT outputIndex = 0;; ++outputIndex) {
IDXGIOutput* output = nullptr;
if (FAILED(adapter->EnumOutputs(outputIndex, &output))) break;
DXGI_OUTPUT_DESC description{};
const bool same = SUCCEEDED(output->GetDesc(&description)) && description.Monitor == monitor;
IDXGIOutput6* output6 = nullptr;
DXGI_OUTPUT_DESC1 description1{};
const bool described = same && SUCCEEDED(output->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void**>(&output6))) && SUCCEEDED(output6->GetDesc1(&description1));
releaseCom(output6);
releaseCom(output);
if (!same) continue;
releaseCom(adapter);
if (!described) return {};
return AgcDriver::DisplayHdrFromOutput(description1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, description1.MaxLuminance, description1.MinLuminance, description1.MaxFullFrameLuminance);
}
releaseCom(adapter);
}
}
#endif
}
HostHdrProbe::~HostHdrProbe() {
Release();
}
void HostHdrProbe::Release() noexcept {
#ifdef _WIN32
auto* dxgiFactory = static_cast<IDXGIFactory1*>(factory);
releaseCom(dxgiFactory);
#endif
factory = nullptr;
monitor = nullptr;
}
void HostHdrProbe::Poll(SDL_Window* window) {
if (window == nullptr) throw std::runtime_error("VideoOut: the HDR probe needs the window");
#ifdef _WIN32
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info) != SDL_TRUE || info.subsystem != SDL_SYSWM_WINDOWS) {
if (!published) AgcDriverSetHostDisplayHdr_nid_postfix({});
published = true;
return;
}
const HMONITOR current = MonitorFromWindow(info.info.win.window, MONITOR_DEFAULTTONEAREST);
auto* dxgiFactory = static_cast<IDXGIFactory1*>(factory);
if (published && current == monitor && (dxgiFactory == nullptr || dxgiFactory->IsCurrent())) return;
releaseCom(dxgiFactory);
factory = nullptr;
monitor = current;
published = true;
if (FAILED(CreateDXGIFactory1(__uuidof(IDXGIFactory1), reinterpret_cast<void**>(&dxgiFactory)))) {
AgcDriverSetHostDisplayHdr_nid_postfix({});
return;
}
factory = dxgiFactory;
AgcDriverSetHostDisplayHdr_nid_postfix(describeMonitor(dxgiFactory, current));
return;
#else
if (published) return;
AgcDriverSetHostDisplayHdr_nid_postfix({});
#endif
published = true;
}