Browse Source

improve vaapi driver health check (#2047)

* improve vaapi driver health check

* fix duplicate check

* cleanup again
pull/2050/head
Jason Dove 3 days ago committed by GitHub
parent
commit
5c8489cbed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 2
      ErsatzTV.FFmpeg/Capabilities/VaapiHardwareCapabilities.cs
  3. 80
      ErsatzTV.Infrastructure/Health/Checks/VaapiDriverHealthCheck.cs

2
CHANGELOG.md

@ -32,6 +32,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -32,6 +32,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add environment variable `ETV_DISABLE_VULKAN`
- Any non-empty value will disable use of Vulkan acceleration and force software tonemapping
- This may be needed with misbehaving NVIDIA drivers on Windows
- Add health check error when invalid VAAPI device and VAAPI driver combination is used in an active ffmpeg profile
- This makes it obvious when hardware acceleration will not work as configured
### Changed
- Start to make UI minimally responsive (functional on smaller screens)

2
ErsatzTV.FFmpeg/Capabilities/VaapiHardwareCapabilities.cs

@ -15,6 +15,8 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities @@ -15,6 +15,8 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities
_logger = logger;
}
public int EntrypointCount => _profileEntrypoints.Count;
public FFmpegCapability CanDecode(
string videoFormat,
Option<string> videoProfile,

80
ErsatzTV.Infrastructure/Health/Checks/VaapiDriverHealthCheck.cs

@ -1,35 +1,81 @@ @@ -1,35 +1,81 @@
using ErsatzTV.Core.Domain;
using System.Collections.Immutable;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Health;
using ErsatzTV.Core.Health.Checks;
using ErsatzTV.FFmpeg;
using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Infrastructure.Health.Checks;
public class VaapiDriverHealthCheck : BaseHealthCheck, IVaapiDriverHealthCheck
public class VaapiDriverHealthCheck(
IHardwareCapabilitiesFactory hardwareCapabilitiesFactory,
IDbContextFactory<TvContext> dbContextFactory)
: BaseHealthCheck, IVaapiDriverHealthCheck
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public VaapiDriverHealthCheck(IDbContextFactory<TvContext> dbContextFactory) =>
_dbContextFactory = dbContextFactory;
public override string Title => "VAAPI Driver";
public async Task<HealthCheckResult> Check(CancellationToken cancellationToken)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
List<FFmpegProfile> profiles = await dbContext.FFmpegProfiles
.Filter(p => p.HardwareAcceleration == HardwareAccelerationKind.Vaapi)
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
List<Channel> channels = await dbContext.Channels
.AsNoTracking()
.ToListAsync(cancellationToken);
var channelFFmpegProfiles = channels
.Map(c => c.FFmpegProfileId)
.ToImmutableHashSet();
List<FFmpegProfile> ffmpegProfiles = await dbContext.FFmpegProfiles
.AsNoTracking()
.Include(p => p.Resolution)
.ToListAsync(cancellationToken);
if (profiles.Count == 0)
var activeFFmpegProfiles = ffmpegProfiles
.Filter(f => channelFFmpegProfiles.Contains(f.Id))
.ToList();
if (activeFFmpegProfiles.Count == 0)
{
return NotApplicableResult();
}
Option<string> maybeFFmpegPath = await dbContext.ConfigElements.GetValue<string>(ConfigElementKey.FFmpegPath);
if (maybeFFmpegPath.IsNone)
{
return NotApplicableResult();
}
foreach (string ffmpegPath in maybeFFmpegPath)
{
IFFmpegCapabilities ffmpegCapabilities = await hardwareCapabilitiesFactory.GetFFmpegCapabilities(ffmpegPath);
foreach (FFmpegProfile profile in activeFFmpegProfiles)
{
Option<string> vaapiDriver = VaapiDriverName(profile.VaapiDriver);
var defaultProfiles = profiles
IHardwareCapabilities capabilities = await hardwareCapabilitiesFactory.GetHardwareCapabilities(
ffmpegCapabilities,
ffmpegPath,
HardwareAccelerationMode.Vaapi,
profile.VaapiDisplay,
vaapiDriver,
profile.VaapiDevice
);
if (capabilities is VaapiHardwareCapabilities { EntrypointCount: 0 } or NoHardwareCapabilities)
{
return FailResult(
$"FFmpeg Profile {profile.Name} is using device and driver combination ({profile.VaapiDevice} and {profile.VaapiDriver}) that reports no capabilities. Hardware Acceleration WILL NOT WORK as configured.");
}
}
}
var defaultProfiles = activeFFmpegProfiles
.Filter(p => p.VaapiDriver == VaapiDriver.Default)
.ToList();
@ -38,4 +84,14 @@ public class VaapiDriverHealthCheck : BaseHealthCheck, IVaapiDriverHealthCheck @@ -38,4 +84,14 @@ public class VaapiDriverHealthCheck : BaseHealthCheck, IVaapiDriverHealthCheck
$"{defaultProfiles.Count} FFmpeg Profile{(defaultProfiles.Count > 1 ? "s are" : " is")} set to use Default VAAPI Driver; selecting iHD (Gen 8+) or i965 (up to Gen 9) may offer better performance with Intel iGPU")
: OkResult();
}
private static Option<string> VaapiDriverName(VaapiDriver driver) =>
driver switch
{
VaapiDriver.i965 => "i965",
VaapiDriver.iHD => "iHD",
VaapiDriver.RadeonSI => "radeonsi",
VaapiDriver.Nouveau => "nouveau",
_ => Option<string>.None
};
}

Loading…
Cancel
Save