All the Small Things

Hi everyone-

Here’s the latest.

Sprite Batching for Lots of Small Rectangles

Turns out that GPUs aren’t great at filling lots of very small rectangles (less than 2 pixels wide or high). This isn’t a Direct2D-specific issue; it’s just the nature of how they work. In certain cases the JUCE software renderer performs significantly better at filling lots of tiny, flat-colored rectangles.

For example, painting 100,000 1x1 solid-colored rectangles takes about 20 msec per frame on my machine with the software renderer. Using Direct2D’s FillRectangle call takes about 50 msec; that’s obviously much worse. Direct2D FillRectangle wins out with larger rectangles, but there’s still a performance gap.

I’ve been really struggling with this one, but I think I’ve got a really nice solution: sprite batching.

Direct2D on Windows 10 and 11 supports sprite batching for drawing thousands of bitmaps with a single call for things like particle simulations. This turns out to work very well for this problem; sprites can be rescaled and colored, so I just created a single white rectangle bitmap and used that over and over again with recoloring to fill rectangle lists.

This made a big performance difference - painting 100,000 rectangles now takes about 3 msec per frame.

The only downside is that sprite batching is only supported on Windows 10 and 11.

To take advantage of sprite batching, call Graphics::fillRectList with a solid color fill.

IPC Metrics

I’ve added a lot of real-time instrumentation to the Direct2D code, but I could only access the various paint statistics from within my own app. Paint metrics are now available through a named pipe IPC; this means the stats can be read and displayed in real-time without any real impact on the app under test.

This is opt-in; IPC is only available if you #define JUCE_DIRECT2D_METRICS=1.

I built a separate app to display the stats; if anyone wants the stat display app or more information on the IPC interface just let me know.

Path caching default

Paths are no longer cached by default. You can enable caching for any Path by just calling Path::setCacheEnabled

Other stuff

  • Fixed drop shadow positioning
  • Fixed Image brushes for single-channel and RGB images
  • Fixed applying the fill type transform for image brushes
  • Fixed the source area origin for drawImage
  • Fixed clearing the background for transparent images
  • Fixed calculating the hash for stroked geometry realization caching
  • Check the maximum bitmap size when creating an Image
  • Workaround for DPI scaling VST child windows
  • Fix DPI scaling for setBufferedToImage

All the best-

Matt

20 Likes

Sorry to bump this thread again. @matt Do you have any suggestion on path caching? From intuition, I should enable caching for a relatively static path (e.g., the filter response curve) and disable caching for a path that updates frequently (e.g., FFT spectrum path). Am I correct?

Hi @zsliu98 - yes, that’s what I recommend.

Matt

1 Like