stride3d/stride · error · ArgumentNullException

ArgumentNullException (targetProfiles)

Error message

ArgumentNullException (targetProfiles)

What it means

FindClosestMatchingDisplayMode requires a non-empty set of target GraphicsProfiles to map onto D3D feature levels when querying the closest matching display mode. An empty span carries no profile information, so the library throws ArgumentNullException (named 'targetProfiles') immediately instead of issuing a meaningless D3D12 query.

Solutions

  1. Ensure at least one GraphicsProfile is in the span before calling, e.g. fall back to the device's current/minimum supported profile
  2. If computing profiles dynamically, validate the list and throw/skip earlier with a clear message
  3. Pass device.Features.Profile (or the highest supported profile) when the caller has no explicit preference

Example fix

// before
output.FindClosestMatchingDisplayMode(ReadOnlySpan<GraphicsProfile>.Empty, mode);
// after
var profiles = new[] { GraphicsProfile.Level_10_0 };
output.FindClosestMatchingDisplayMode(profiles, mode);
Defensive patterns

Strategy: validation

Validate before calling

if (profiles == null || profiles.Length == 0) throw new ArgumentException("At least one GraphicsProfile is required", nameof(profiles));

Type guard

bool HasProfiles(ReadOnlySpan<GraphicsProfile> p) => !p.IsEmpty;

Try / catch

try { mode = output.FindClosestMatchingDisplayMode(profiles, mode); } catch (ArgumentNullException) { mode = output.CurrentDisplayMode; }

Prevention

When it happens

Trigger: Calling GraphicsOutput.FindClosestMatchingDisplayMode with a default/empty ReadOnlySpan<GraphicsProfile> (e.g. Array.Empty<GraphicsProfile>(), stackalloc of length 0, or a filtered profile list that ended up empty).

Common situations: Building the profile list dynamically from device capabilities and a filter removing all entries; passing a span constructed from an empty collection; refactoring that changed GraphicsProfile[] to a span without re-checking length.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/702a263e2234becb. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Direct3D12/GraphicsOutput.Direct3D12.cs:94

    ///   <para>
    ///     When determining the closest value for a particular field, previously matched fields are used to filter the display mode list choices, and other fields are ignored.
    ///     For example, when matching resolution, the display mode list will have already been filtered by a certain pixel format, while the refresh rate is ignored.
    ///   </para>
    ///   <para>
    ///     This ordering doesn't define the absolute ordering for every usage scenario of <see cref="FindClosestMatchingDisplayMode"/>, because the application can choose some
    ///     values initially, effectively changing the order that fields are chosen. Fields of the display mode are matched one at a time, generally in a specified order.
    ///     If a field is unspecified, this method gravitates toward the values for the desktop related to this output. If this output is not part of the desktop, then
    ///     the default desktop output is used to find values.
    ///   </para>
    ///   <para>
    ///     If an application uses a fully unspecified display mode, <see cref="FindClosestMatchingDisplayMode"/> will typically return a display mode that matches the
    ///     desktop settings for this output.
    ///   </para>
    /// </remarks>
    public DisplayMode FindClosestMatchingDisplayMode(ReadOnlySpan<GraphicsProfile> targetProfiles, DisplayMode modeToMatch)
    {
        if (targetProfiles.IsEmpty)
            throw new ArgumentNullException(nameof(targetProfiles));

        var d3d12 = D3D12.GetApi();

        // NOTE: Assume the same underlying integer type
        Debug.Assert(sizeof(GraphicsProfile) == sizeof(D3DFeatureLevel));
        var featureLevels = targetProfiles.As<GraphicsProfile, D3DFeatureLevel>();

        HResult result = default;

        var nativeAdapter = Adapter.NativeAdapter.AsIUnknown();
        ComPtr<ID3D12Device> deviceTemp = null;

        for (int i = 0; i < featureLevels.Length; i++)
        {
            var featureLevelToTry = featureLevels[i];

            // Create Device D3D12 with feature Level based on profile
            result = d3d12.CreateDevice(nativeAdapter, featureLevelToTry, out deviceTemp);

View on GitHub (pinned to 96fad776d2)