Files
plezy/windows/runner/main.cpp
T
edde746 628fd21ec3 fix(windows): keep the video visible behind the OSD by pinning the Skia renderer
After 2.17.1 the video went fully black on Windows for as long as the player
UI was on screen and came back the instant it faded out. Audio was never
affected, mpv.conf made no difference, and 2.17.0 on the same machine and
driver was fine.

2.17.1 moved to Flutter 3.47.1, which made Impeller the default Windows
renderer. Plezy is unusually exposed to that switch: the patched engine
presents the UI on a topmost DirectComposition visual that DWM blends over the
mpv video child, so the video is only as visible as the presented frame's
per-pixel alpha says it is. When Impeller's GLES backend gets that alpha wrong,
the OSD's full-screen scrim presents opaque and hides the video outright;
unmounting the controls presents a transparent frame again, which is why the
picture tracked the UI exactly.

Opt out through the embedder Impeller switch that 3.47 added. Unlike
FLUTTER_ENGINE_SWITCHES it applies to release builds, and it restores the
renderer every release up to 2.17.0 shipped without touching the engine patches.

close #2127
2026-08-26 03:15:59 +02:00

77 lines
2.9 KiB
C++

#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <windows.h>
#include "flutter_window.h"
#include "mpv/display_mode_manager.h"
#include "utils.h"
int APIENTRY
wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t* command_line, _In_ int show_command) {
// Plezy requires the bundled flutter-plezy engine, which presents the Flutter
// UI on a topmost DirectComposition visual when FLUTTER_WINDOWS_DCOMP is set.
// The mpv video window is then a plain child composed beneath the UI in the
// same HWND: window capture (Discord/OBS) works, there is no transparency
// hack, and min/max animations are native. Must be set before the engine is
// created. (On a stock engine the flag is a no-op and compositing breaks.)
::SetEnvironmentVariableW(L"FLUTTER_WINDOWS_DCOMP", L"1");
HANDLE mutex = CreateMutex(nullptr, TRUE, L"com.edde746.Plezy.SingleInstance");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
HWND existing = FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"Plezy");
if (existing) {
ShowWindow(existing, SW_RESTORE);
SetForegroundWindow(existing);
}
CloseHandle(mutex);
return EXIT_SUCCESS;
}
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM for Win32 libraries and plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data");
project.set_ui_thread_policy(flutter::UIThreadPolicy::RunOnSeparateThread);
// Keep rendering with Skia. Flutter 3.47 made Impeller the default Windows
// renderer, but the DirectComposition presentation above is only correct
// when the frame's per-pixel alpha is exact: DWM blends the UI visual over
// the mpv video child, so a frame that presents opaque where it should be
// translucent hides the video outright. Impeller's GLES backend gets that
// alpha wrong on some drivers - the video area went black for as long as
// the player OSD was on screen (#2127). Every release up to 2.17.0 rendered
// with Skia; keep it until Impeller composites the alpha correctly.
project.set_impeller_switch(flutter::ImpellerSwitch::Disabled);
std::vector<std::string> command_line_arguments = GetCommandLineArguments();
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"Plezy", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
// Recover display mode if a prior crash left it changed.
mpv::DisplayModeManager::RecoverIfNeeded();
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
::CoUninitialize();
CloseHandle(mutex);
return EXIT_SUCCESS;
}