Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions StabilityMatrix.Avalonia/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
<StyleInclude Source="Controls/Inference/WanModelCard.axaml" />
<StyleInclude Source="Controls/Inference/PlasmaNoiseCard.axaml" />
<StyleInclude Source="Controls/Inference/NrsCard.axaml" />
<StyleInclude Source="Controls/Inference/CfzCudnnToggleCard.axaml" />
<labs:ControlThemes />

<Style Selector="DockControl">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:StabilityMatrix.Avalonia.Controls"
xmlns:mocks="clr-namespace:StabilityMatrix.Avalonia.DesignData"
xmlns:vmInference="clr-namespace:StabilityMatrix.Avalonia.ViewModels.Inference"
x:DataType="vmInference:CfzCudnnToggleCardViewModel">
<Design.PreviewWith>
<controls:CfzCudnnToggleCard Width="400" />
</Design.PreviewWith>

<Style Selector="controls|CfzCudnnToggleCard">
<Setter Property="Template">
<ControlTemplate>
<controls:Card x:Name="PART_Card">
<StackPanel Spacing="8">
<TextBlock Text="Enable CUDNN" FontSize="14" FontWeight="Bold" />
<ToggleSwitch
IsChecked="{Binding EnableCudnn}"
Margin="8,0,4,0"
HorizontalAlignment="Stretch" />

<TextBlock Text="CUDNN Benchmark" FontSize="14" FontWeight="Bold" />
<ToggleSwitch
IsChecked="{Binding CudnnBenchmark}"
Margin="8,0,4,0"
HorizontalAlignment="Stretch" />
</StackPanel>
</controls:Card>
</ControlTemplate>
</Setter>
</Style>
</Styles>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Injectio.Attributes;

namespace StabilityMatrix.Avalonia.Controls;

[RegisterTransient<CfzCudnnToggleCard>]
public class CfzCudnnToggleCard : TemplatedControlBase;
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base;
[JsonDerivedType(typeof(RescaleCfgCardViewModel), RescaleCfgCardViewModel.ModuleKey)]
[JsonDerivedType(typeof(PlasmaNoiseCardViewModel), PlasmaNoiseCardViewModel.ModuleKey)]
[JsonDerivedType(typeof(NrsCardViewModel), NrsCardViewModel.ModuleKey)]
[JsonDerivedType(typeof(CfzCudnnToggleCardViewModel), CfzCudnnToggleCardViewModel.ModuleKey)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve code organization and maintainability, please keep [JsonDerivedType] attributes sorted alphabetically by the type name. CfzCudnnToggleCardViewModel should be placed before ControlNetCardViewModel.

[JsonDerivedType(typeof(FreeUModule))]
[JsonDerivedType(typeof(HiresFixModule))]
[JsonDerivedType(typeof(FluxHiresFixModule))]
Expand All @@ -41,6 +42,7 @@ namespace StabilityMatrix.Avalonia.ViewModels.Base;
[JsonDerivedType(typeof(RescaleCfgModule))]
[JsonDerivedType(typeof(PlasmaNoiseModule))]
[JsonDerivedType(typeof(NRSModule))]
[JsonDerivedType(typeof(CfzCudnnToggleModule))]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve code organization and maintainability, please keep [JsonDerivedType] attributes sorted alphabetically by the type name. CfzCudnnToggleModule should be placed before ControlNetModule.

public abstract class LoadableViewModelBase : ViewModelBase, IJsonLoadableState
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Injectio.Attributes;
using StabilityMatrix.Avalonia.Controls;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Core.Attributes;

namespace StabilityMatrix.Avalonia.ViewModels.Inference;

[View(typeof(CfzCudnnToggleCard))]
[ManagedService]
[RegisterTransient<CfzCudnnToggleCardViewModel>]
public partial class CfzCudnnToggleCardViewModel : LoadableViewModelBase
{
public const string ModuleKey = "CfzCudnnToggle";

[ObservableProperty]
private bool enableCudnn = false;

[ObservableProperty]
private bool cudnnBenchmark;
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ RunningPackageService runningPackageService
{
modulesCard.AvailableModules = new[]
{
typeof(CfzCudnnToggleModule),
typeof(FaceDetailerModule),
typeof(FluxHiresFixModule),
typeof(UpscalerModule),
typeof(SaveImageModule),
typeof(FaceDetailerModule)
typeof(UpscalerModule),
};
modulesCard.DefaultModules = new[] { typeof(FluxHiresFixModule), typeof(UpscalerModule) };
modulesCard.InitializeDefaults();
Expand All @@ -121,7 +122,7 @@ protected override void BuildPrompt(BuildPromptEventArgs args)
builder.Connections.Seed = args.SeedOverride switch
{
{ } seed => Convert.ToUInt64(seed),
_ => Convert.ToUInt64(SeedCardViewModel.Seed)
_ => Convert.ToUInt64(SeedCardViewModel.Seed),
};

var applyArgs = args.ToModuleApplyStepEventArgs();
Expand Down Expand Up @@ -217,7 +218,7 @@ CancellationToken cancellationToken
FilesToTransfer = buildPromptArgs.FilesToTransfer,
BatchIndex = i,
// Only clear output images on the first batch
ClearOutputImages = i == 0
ClearOutputImages = i == 0,
};

batchArgs.Add(generationArgs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,11 @@ TabContext tabContext
{
modulesCard.AvailableModules = new[]
{
typeof(CfzCudnnToggleModule),
typeof(FaceDetailerModule),
typeof(HiresFixModule),
typeof(UpscalerModule),
typeof(SaveImageModule),
typeof(FaceDetailerModule)
typeof(UpscalerModule),
};
modulesCard.DefaultModules = new[] { typeof(HiresFixModule), typeof(UpscalerModule) };
modulesCard.InitializeDefaults();
Expand Down Expand Up @@ -158,7 +159,7 @@ protected override void BuildPrompt(BuildPromptEventArgs args)
builder.Connections.Seed = args.SeedOverride switch
{
{ } seed => Convert.ToUInt64(seed),
_ => Convert.ToUInt64(SeedCardViewModel.Seed)
_ => Convert.ToUInt64(SeedCardViewModel.Seed),
};

var applyArgs = args.ToModuleApplyStepEventArgs();
Expand Down Expand Up @@ -319,13 +320,13 @@ CancellationToken cancellationToken
OutputNodeNames = buildPromptArgs.Builder.Connections.OutputNodeNames.ToArray(),
Parameters = SaveStateToParameters(new GenerationParameters()) with
{
Seed = Convert.ToUInt64(seed)
Seed = Convert.ToUInt64(seed),
},
Project = inferenceProject,
FilesToTransfer = buildPromptArgs.FilesToTransfer,
BatchIndex = i,
// Only clear output images on the first batch
ClearOutputImages = i == 0
ClearOutputImages = i == 0,
};

batchArgs.Add(generationArgs);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Linq;
using Injectio.Attributes;
using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes;
using StabilityMatrix.Core.Models.Inference;

namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules;

[ManagedService]
[RegisterTransient<CfzCudnnToggleModule>]
public class CfzCudnnToggleModule : ModuleBase
{
/// <inheritdoc />
public CfzCudnnToggleModule(IServiceManager<ViewModelBase> vmFactory)
: base(vmFactory)
{
Title = "Disable CUDNN (ComfyUI-Zluda)";
}

/// <summary>
/// Applies CUDNN Toggle node between sampler latent output and VAE decode
/// This prevents "GET was unable to find an engine" errors on AMD cards with Zluda
/// </summary>
protected override void OnApplyStep(ModuleApplyStepEventArgs e)
{
// Get the primary connection (can be latent or image)
var primary = e.Builder.Connections.Primary;
if (primary == null)
{
return; // No primary connection to process
}

// Check if primary is a latent (from sampler output)
if (primary.IsT0) // T0 is LatentNodeConnection
{
var latentConnection = primary.AsT0;

// Insert CUDNN toggle node between sampler and VAE decode
var cudnnToggleOutput = e.Nodes.AddTypedNode(
new ComfyNodeBuilder.CUDNNToggleAutoPassthrough

Check failure on line 45 in StabilityMatrix.Avalonia/ViewModels/Inference/Modules/CfzCudnnToggleModule.cs

View workflow job for this annotation

GitHub Actions / build

Required member 'ComfyNodeBuilder.CUDNNToggleAutoPassthrough.CudnnBenchmark' must be set in the object initializer or attribute constructor.

Check failure on line 45 in StabilityMatrix.Avalonia/ViewModels/Inference/Modules/CfzCudnnToggleModule.cs

View workflow job for this annotation

GitHub Actions / build

Required member 'ComfyNodeBuilder.CUDNNToggleAutoPassthrough.EnableCudnn' must be set in the object initializer or attribute constructor.
{
Name = e.Nodes.GetUniqueName("CUDNNToggle"),
Model = null,
Conditioning = null,
Latent = latentConnection, // Pass through the latent from sampler
enable_cudnn = false,

Check failure on line 51 in StabilityMatrix.Avalonia/ViewModels/Inference/Modules/CfzCudnnToggleModule.cs

View workflow job for this annotation

GitHub Actions / build

'ComfyNodeBuilder.CUDNNToggleAutoPassthrough' does not contain a definition for 'enable_cudnn'
cudnn_benchmark = false,

Check failure on line 52 in StabilityMatrix.Avalonia/ViewModels/Inference/Modules/CfzCudnnToggleModule.cs

View workflow job for this annotation

GitHub Actions / build

'ComfyNodeBuilder.CUDNNToggleAutoPassthrough' does not contain a definition for 'cudnn_benchmark'
}
);

// Update the primary connection to use the CUDNN toggle latent output (Output3)
// This ensures VAE decode receives latent from CUDNN toggle instead of directly from sampler
e.Builder.Connections.Primary = cudnnToggleOutput.Output3;
}
}
}
Comment on lines +1 to +61
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The module currently hardcodes enable_cudnn and cudnn_benchmark to false, which doesn't use the values from CfzCudnnToggleCardViewModel. This makes the UI controls for these settings ineffective.

To fix this, you should:

  1. In the CfzCudnnToggleModule constructor, add the CfzCudnnToggleCardViewModel as a card to the module.
  2. Update OnApplyStep to retrieve the view model and use its properties (EnableCudnn and CudnnBenchmark) when creating the CUDNNToggleAutoPassthrough node.
  3. Consider renaming the module Title to "CUDNN Toggle (ComfyUI-Zluda)" to better reflect that it can both enable and disable CUDNN settings.
  4. The using System.Linq; statement is not used and can be removed.

I've included a code suggestion that implements these changes. Note that it uses PascalCase property names (EnableCudnn, CudnnBenchmark) for the CUDNNToggleAutoPassthrough node, which corresponds to another suggestion I've made for ComfyNodeBuilder.cs.

using Injectio.Attributes;
using StabilityMatrix.Avalonia.Models.Inference;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Avalonia.ViewModels.Base;
using StabilityMatrix.Avalonia.ViewModels.Inference;
using StabilityMatrix.Core.Attributes;
using StabilityMatrix.Core.Models.Api.Comfy.Nodes;
using StabilityMatrix.Core.Models.Api.Comfy.NodeTypes;
using StabilityMatrix.Core.Models.Inference;

namespace StabilityMatrix.Avalonia.ViewModels.Inference.Modules;

[ManagedService]
[RegisterTransient<CfzCudnnToggleModule>]
public class CfzCudnnToggleModule : ModuleBase
{
    /// <inheritdoc />
    public CfzCudnnToggleModule(IServiceManager<ViewModelBase> vmFactory)
        : base(vmFactory)
    {
        Title = "CUDNN Toggle (ComfyUI-Zluda)";
        AddCards(vmFactory.Get<CfzCudnnToggleCardViewModel>());
    }

    private CfzCudnnToggleCardViewModel Card => GetCard<CfzCudnnToggleCardViewModel>();

    /// <summary>
    /// Applies CUDNN Toggle node between sampler latent output and VAE decode
    /// This prevents "GET was unable to find an engine" errors on AMD cards with Zluda
    /// </summary>
    protected override void OnApplyStep(ModuleApplyStepEventArgs e)
    {
        // Get the primary connection (can be latent or image)
        var primary = e.Builder.Connections.Primary;
        if (primary == null)
        {
            return; // No primary connection to process
        }

        // Check if primary is a latent (from sampler output)
        if (primary.IsT0) // T0 is LatentNodeConnection
        {
            var latentConnection = primary.AsT0;

            // Insert CUDNN toggle node between sampler and VAE decode
            var cudnnToggleOutput = e.Nodes.AddTypedNode(
                new ComfyNodeBuilder.CUDNNToggleAutoPassthrough
                {
                    Name = e.Nodes.GetUniqueName("CUDNNToggle"),
                    Model = null,
                    Conditioning = null,
                    Latent = latentConnection, // Pass through the latent from sampler
                    EnableCudnn = Card.EnableCudnn,
                    CudnnBenchmark = Card.CudnnBenchmark,
                }
            );

            // Update the primary connection to use the CUDNN toggle latent output (Output3)
            // This ensures VAE decode receives latent from CUDNN toggle instead of directly from sampler
            e.Builder.Connections.Primary = cudnnToggleOutput.Output3;
        }
    }
}

14 changes: 14 additions & 0 deletions StabilityMatrix.Core/Models/Api/Comfy/Nodes/ComfyNodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,20 @@ public record BrownNoise : ComfyTypedNodeBase<ImageNodeConnection>
public required ulong Seed { get; init; } = 0;
}

/// <summary>
/// CUDNN Toggle node for controlling CUDA Deep Neural Network library settings (CUDNNToggleAutoPassthrough)
/// </summary>
[TypedNodeOptions(Name = "CUDNNToggleAutoPassthrough")]
public record CUDNNToggleAutoPassthrough
: ComfyTypedNodeBase<ModelNodeConnection, ConditioningNodeConnection, LatentNodeConnection>
{
public ModelNodeConnection? Model { get; init; }
public ConditioningNodeConnection? Conditioning { get; init; }
public LatentNodeConnection? Latent { get; init; }
public required bool EnableCudnn { get; init; } = false;
public required bool CudnnBenchmark { get; init; } = false;
}

/// <summary>
/// Custom KSampler node using alternative noise distribution (Lykos_JDC_PlasmaSampler)
/// </summary>
Expand Down
Loading