MiniMax-H3 FL2VA on Dual RTX 3060s: My Journey from ComfyUI to stable-diffusion.cpp

•7 min read

I wanted to run MiniMax-H3 FL2VA locally on my dual RTX 3060 12GB setup and generate 9:16 videos at 1080 × 1920. Both timing results in this article use the 8-step turbo LoRA-baked model.

My Udero GGUF model files are available here: Udero MiniMax-H3 Turbo GGUF on Hugging Face.

I started with ComfyUI. After some experimentation and a few code patches, I managed to get 1080p generation working across both GPUs. But then I ran into another problem: model loading and unloading took too much time.

I switched to stable-diffusion.cpp (sd-cli). In my tests, it was faster and worked on a single GPU, but I couldn't reach the same resolution. I eventually settled on stable-diffusion.cpp at 928 pixels wide because the faster workflow was worth the resolution trade-off for me.

Here is what I changed, what I measured, and why I made that choice.

1. Making 1080p work in ComfyUI

The first challenge was memory. My two RTX 3060s provide 24 GB of combined VRAM, but that doesn't behave like one unified 24 GB GPU. Model weights, intermediate activations and working buffers still need to fit on the devices where their operations execute.

Increasing video resolution and frame count makes this harder.

For a 9:16 video at 1080 × 1920:

  • Pixels per frame = 1080 × 1920 = 2,073,600
  • Total pixel positions for 73 frames = 2,073,600 × 73 = 151,372,800

That's about 151.4 million pixel positions across the video.

I found that loading the model weights was only part of the problem. Intermediate tensors created during inference and the memory required for VAE decoding were also important bottlenecks.

I addressed these by patching the ComfyUI MiniMax implementation.

FFN activation/token chunking

The transformer's feed-forward network (FFN) expands the token representation into a wider intermediate tensor. With a long video sequence, this tensor can consume several GB of memory.

Consider a simplified example with 100,000 tokens and an intermediate width of 16,384 elements. If the tensor uses BF16, each element occupies 2 bytes:

  • Memory = 100,000 × 16,384 × 2
  • Memory = 3,276,800,000 bytes
  • That's approximately 3.28 GB, or 3.05 GiB.

I added token chunking to the MiniMax MLP path so that long sequences were processed in chunks of 12,000 tokens rather than all at once.

For the same hypothetical dimensions:

  • Chunk memory = 12,000 × 16,384 × 2
  • Chunk memory = 393,216,000 bytes
  • That's approximately 393 MB, or 375 MiB.

Compared with processing all 100,000 tokens in one operation, this reduces the size of that particular intermediate tensor by approximately 88%.

This does not mean total VRAM usage drops by 88%. The model weights, input/output tensors and other buffers still occupy memory. However, it substantially reduces the peak memory required for the FFN expansion.

Temporal VAE latent chunking

The second patch addressed video decoding.

After diffusion sampling, the VAE must convert the latent video into actual frames. Decoding a long video in one pass can create large intermediate feature maps and cause another out-of-memory failure.

I added temporal latent chunking so the VAE could decode smaller sections of the video, with overlap handling between adjacent chunks.

This reduced the amount of data the decoder needed to process at once. It addressed a separate memory bottleneck from FFN chunking: one helped during transformer computation, while the other helped during VAE decoding.

Splitting transformer blocks across both GPUs

I also used a multi-GPU splitter to distribute the 50 transformer blocks across the two RTX 3060s:

  • GPU 0: blocks 0–21.
  • GPU 1: blocks 22–49.

The intermediate hidden-state tensor was transferred between the GPUs so the second group of blocks could continue processing it.

This distributed the transformer weights across both cards rather than requiring all the blocks to fit on one GPU. The combination of FFN chunking, temporal VAE latent chunking and transformer-block splitting allowed me to get 1080 × 1920 video generation working in ComfyUI.

2. The problem with ComfyUI: model loading and unloading

Getting 1080p working was a major step, but it didn't solve everything.

My workflow involved large models, and loading, unloading and switching between them took considerable time. The overall experience wasn't just about the time spent generating the video; model-management overhead also mattered.

I wanted a workflow that was faster to start, easier to switch between and less dependent on managing a complex multi-model pipeline.

That led me to try stable-diffusion.cpp.

3. Switching to stable-diffusion.cpp

stable-diffusion.cpp uses a C++ inference implementation built around GGML. In my tests, it offered faster execution and lower model-management overhead for my chosen workflow.

I couldn't get the same 1080 × 1920 output with my tested stable-diffusion.cpp configuration. I also couldn't reproduce the same combination of FFN token chunking, temporal VAE latent chunking and transformer-block splitting that I had implemented in ComfyUI.

However, stable-diffusion.cpp could run on a single RTX 3060 when I reduced the output width to 928 pixels while keeping the 9:16 aspect ratio. That left my second GPU available for other work.

4. Actual results: resolution, GPU use and time

Here are the results from my setup, using the same 8-step turbo LoRA-baked model:

MetricComfyUIstable-diffusion.cpp
Output resolution1080 × 1920Approximately 928 × 1650
GPUs used2 × RTX 3060 12GB1 × RTX 3060 12GB
Generation time42 minutes23 minutes
Pixels per frame2,073,6001,531,200
Relative pixel count100%73.8%

At 928 × 1650, the output contains:

  • Pixels per frame = 928 × 1650 = 1,531,200
  • That's about 1.53 million pixels per frame.
  • Across 73 frames = 1,531,200 × 73 = 111,777,600 pixel positions.

The 1080 × 1920 output has approximately 35.4% more pixels per frame than the 928 × 1650 output. For 73 frames, that's about 151.4 million pixel positions versus 111.8 million.

ComfyUI took 42 minutes to generate the 1080p video using both GPUs. stable-diffusion.cpp took 23 minutes to generate the lower-resolution video using one GPU.

The time difference is:

  • Time saved = 42 − 23 = 19 minutes.
  • Percentage reduction = (19 ÷ 42) × 100 = approximately 45.2%.

So the stable-diffusion.cpp run took about 45% less time, while using one GPU instead of two.

This isn't an apples-to-apples performance benchmark because the resolutions and GPU configurations differ. The result reflects the practical trade-off I encountered: ComfyUI delivered the higher resolution, while stable-diffusion.cpp delivered a faster single-GPU workflow at a lower resolution.

These pixel counts also don't directly predict VRAM usage or generation time. The model operates on compressed latents, and attention, activation memory and VAE decoding have their own costs. Still, the calculations help illustrate the difference in output size.

5. Why I settled on one GPU

My final choice was stable-diffusion.cpp on a single RTX 3060, generating at 928 pixels wide.

I gave up 1080p output, but gained a faster workflow, quicker model loading and unloading, and the ability to leave the second GPU available for other work.

ComfyUI remained the solution that got my 1080p workflow working, thanks to the code patches and multi-GPU setup. But for my day-to-day workflow, the speed and simplicity of stable-diffusion.cpp were more useful than the higher resolution.

This isn't a universal comparison between the two frameworks. It reflects my particular model, patches, hardware and workload. Another model or software version may behave differently.

Final takeaway

The biggest lesson was that running a large video diffusion model isn't just about fitting its weights into VRAM.

I had to address three separate memory problems in ComfyUI: FFN activation growth, VAE decoding and transformer placement across two GPUs. Those changes made 1080p possible, but model loading and unloading remained a significant overhead.

My measured results were:

  • ComfyUI: 1080 × 1920, both RTX 3060 GPUs, 42 minutes, using the 8-step turbo LoRA-baked model.
  • stable-diffusion.cpp: Approximately 928 × 1650, one RTX 3060 GPU, 23 minutes, using the same 8-step turbo LoRA-baked model.

Model: Udero MiniMax-H3 Turbo GGUF.

I started by trying to achieve the highest possible resolution. I ended up choosing the workflow that gave me a better balance of speed, memory usage and convenience.

Enjoyed this article?

Subscribe to get the latest deep dives on Linux and Security delivered to your inbox.

Subscribe to Newsletter

Get the latest articles on Linux, cryptography, and security delivered to your inbox.

No spam, unsubscribe anytime.

Comments Coming Soon

We are building a privacy-focused, secure commenting system. Stay tuned!