# I wrote a bit about "jank" in JUCE

**URL:** <https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112>\
**Category:** General JUCE discussion\
**Created:** [April 21, 2022, 4:06pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112 "2022-04-21T16:06:44Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 21, 2022, 4:06pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/1 "2022-04-21T16:06:44Z")

</div>

> **[Dealing with UI jank in the JUCE framework · Melatonin](https://melatonin.dev/blog/dealing-with-jank-in-juce/)**
>
> If you say jank 10 times in a row, the jank fairy will come and animate that modal window for you.

Curious what other people’s experiences have been and if anyone has any dark art “repaint” secrets I don’t already know…

---

<div class="post-metadata">

**Author:** ![ImJimmi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/imjimmi/32/10843_2.png) [@ImJimmi](https://forum.juce.com/u/ImJimmi)\
**Post date:** [April 21, 2022, 4:38pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/2 "2022-04-21T16:38:22Z")

</div>

I always assumed the issue came from the fact the JUCE was originally built for waveform, which has a fairly basic UI and so never needed support for animations and whatnot.

Just simple things like not having a consistent way of styling widgets always irritates me - the other day I wanted to change the colour of the rectangle drawn around a `juce::ToggleButton`… guess what colour ID it uses? Probably `outlineColourId` right? Nope, [`tickDisabledColourId`](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/lookandfeel/juce_LookAndFeel_V4.cpp#L364).

Paint debugging is a tricky one. JUCE does have the `JUCE_ENABLE_REPAINT_DEBUGGING` macro that will flash components when they’re repainted… however that’s misleading as the OS will sometimes draw more, or less than what JUCE flags. MacOS has a similar tool to highlight areas of the screen being redrawn (Quartz Debug), maybe there’s one for Windows too?

Screen recording janky UIs is a good tip, you can then step through frame-by-frame to see what’s really going on. I’ve also found that using the slow-motion mode on my phone to record the screen can also be useful because the way your monitor actually refreshes can completely change how your UI looks when it comes to animations - I used to use a crappy old lcd TV as a monitor and recording that in slow-mo showed how it would sweep the screen from top to bottom as it redrew, and a lot of the jank I was seeing was just because of how slow it did that!

Hopefully some of the changes in JUCE 7 around synching with screen refresh rates may improve things here?

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 21, 2022, 5:16pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/3 "2022-04-21T17:16:32Z")

</div>

> [@ImJimmi](#):
>
> I used to use a crappy old lcd TV as a monitor and recording that in slow-mo showed how it would sweep the screen from top to bottom as it redrew, and a lot of the jank I was seeing was just because of how slow it did that!

Ha that’s great!

> [@ImJimmi](#):
>
> JUCE was originally built for waveform, which has a fairly basic UI and so never needed support for animations and whatnot.

Hopefully I didn’t come off as too critical of JUCE. I do feel like UI has evolved a fair amount in the last 10+ years and there’s a bit of catch up for JUCE (speaking of, love your [stack blur PR](https://github.com/juce-framework/JUCE/pull/1049), it’s a pre-req for efficient shadows!). But ultimately dealing with jank seems inevitable in a framework that has low level manual (er, semi-automatic?) paint timing. If anything, some more tooling and docs around it would be nice!

---

<div class="post-metadata">

**Author:** ![Mrugalla](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/mrugalla/32/13092_2.png) [@Mrugalla](https://forum.juce.com/u/Mrugalla)\
**Post date:** [April 21, 2022, 7:24pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/4 "2022-04-21T19:24:57Z")

</div>

one thing that you maybe forgot about in your article was that you can always just setBufferedImage(true) on a component in order to make it bypass all its automatic repaint calls, except for the ones apearing at the end of resized(). because then you can really surgically define when to repaint stuff manually

---

<div class="post-metadata">

**Author:** ![ImJimmi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/imjimmi/32/10843_2.png) [@ImJimmi](https://forum.juce.com/u/ImJimmi)\
**Post date:** [April 21, 2022, 7:44pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/5 "2022-04-21T19:44:14Z")

</div>

In most cases it’s actually slower to render a component from an image, so you shouldn’t just blindly go calling `setBufferedToImage(true)` on things without benchmarking them. Text is one place where it _is_ almost always faster to render from an image, so that might improve the case of the caret in the text editor.

---

<div class="post-metadata">

**Author:** ![Mrugalla](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/mrugalla/32/13092_2.png) [@Mrugalla](https://forum.juce.com/u/Mrugalla)\
**Post date:** [April 21, 2022, 8:16pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/6 "2022-04-21T20:16:10Z")

</div>

maybe it would be cool if juce::Component had a new method called reducePaintCalls() or so that only has this “less-paint calls”-ish property, but without the image-lookup table

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 21, 2022, 8:24pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/7 "2022-04-21T20:24:07Z")

</div>

> [@Mrugalla](#):
>
> you can always just setBufferedImage(true) on a component in order to make it bypass all its automatic repaint calls, except for the ones apearing at the end of resized(). because then you can really surgically define when to repaint stuff manually

Ahh, true, I totally ignored this. I was under the impression a component’s `cachedImage` invalidates on any `repaint()` call. So for example, my `CaretComponent` calls `setVisible` on itself, which calls `repaint` on itself, which calls `repaint` on the TextEditor, which calls `repaint` on the Form its in… so all of those components would have their cache invalidated. So, I don’t think it would rescue me from “jank” caused by repaint calls (which are everywhere!).

Actually, maybe like others, I’m generally unclear about the “good” `setBufferedToImage` use cases.

The docs are a bit murky, but [reading the code it seems that `cachedImage->paint` is only ever called in `paintWithinParentContext`](https://github.com/juce-framework/JUCE/blob/master/modules/juce_gui_basics/components/juce_Component.cpp#L1991) which is called from `paintComponentAndChildren` (which recursively goes through the hierarchy top down painting children)

So if I’m understanding correctly, `setBufferedToImage` would be better named `cacheComponentAndChildrenUntilRepaint` — the cache is only used when the component’s _parent_ is painting and is calling `paintComponentAndChildren` (opposite direction of what’s happening with the caret example).

> [@ImJimmi](#):
>
> Text is one place where it _is_ almost always faster to render from an image, so that might improve the case of the caret in the text editor.

Oooh, this makes sense!

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 21, 2022, 8:51pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/8 "2022-04-21T20:51:00Z")

</div>

> [@Mrugalla](#):
>
> maybe it would be cool if juce::Component had a new method called reducePaintCalls()

I thought `setOpaque` was supposed to work this way ([the whole point of calling `repaint()` on the parent for transparent components is you need to repaint what’s “behind” the changing component](https://forum.juce.com/t/repaint-without-parent-repaint/15550/4)), but it’s late and I’m not seeing it in the code…

---

<div class="post-metadata">

**Author:** ![ImJimmi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/imjimmi/32/10843_2.png) [@ImJimmi](https://forum.juce.com/u/ImJimmi)\
**Post date:** [April 21, 2022, 9:55pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/9 "2022-04-21T21:55:39Z")

</div>

> [@sudara](#):
>
> I was under the impression a component’s `cachedImage` invalidates on any `repaint()` call.

[That is the case, yes.](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L1945)

When you call `repaint()` on a component that’s using a cached image, if that component is visible any part of the image that overlaps the area being redrawn (because it’s not always the entire component, see below) will be invalidated. In turn this will mean the `paint()` method will be invoked on that component so as to update the invalidated portion of the image.

> [@sudara](#):
>
> So for example, my `CaretComponent` calls `setVisible` on itself, which calls `repaint` on itself, which calls `repaint` on the TextEditor

`juce::Component::setVisible()` will call `repaint()` on the component in question if it has just been made visible - if not it will call `repaint()` on the _parent_. [See here.](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L589)

When you call `repaint()` on a component, you’re not saying “please call `paint()` on this component at some point in the near future”. What you’re doing is first invalidating the cache, if the component on which `repaint()` was called is set to buffer to an image, then telling the _OS_, “this portion of the screen needs to be redrawn on the next update please”. The OS will then come back around at some point and tell the `ComponentPeer` which portions of the screen need to be redrawn. See [`juce::ComponentPeer::handlePaint()`](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp#L132).

Then, each component will draw itself and any of its children [_that overlap the portion of the screen marked for repainting_](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L2027). Any component that’s using a cached image will obviously just draw the cached image (which will call `paint()` if the cache was invalidated to update the image), all other components will then just call `paint()`. What this means is that in general, when you flag a component as needing to repaint, it, its parent, and all of its ancestors will be drawn, but its siblings won’t (unless they overlap).

In the case of your caret 🥕 - when you call `repaint()` on the caret you’re saying that small portion of the screen needs to redraw. If you haven’t called `setBufferedToImage(true)` on the text editor, then every single time the caret’s made invisible, your _entire_ text editor is being rendered since the `paint()` method will be invoked (but even though you paint the entire component, only the small portion under the caret is actually being ‘used’ because the rest is outside the clip bounds of the context). Text rendering is very expensive, so if your text editor contains a lot of text this process is going to be very slow. If you call `setBufferedToImage(true)` on the editor, when the caret is made invisible only a tiny portion of the cached image will be drawn to the screen which will be extremely cheap.

> [@sudara](#):
>
> Actually, maybe like others, I’m generally unclear about the “good” `setBufferedToImage` use cases.

In general, if a component takes longer to draw in its `paint()` method than it would to draw an image of the same size, call `setBufferedToImage(true)` on it. If in doubt, profile your app with it turned off, profile it with it turned on, and choose the one that gave the best performance!

> [@sudara](#):
>
> So if I’m understanding correctly, `setBufferedToImage` would be better named `cacheComponentAndChildrenUntilRepaint` — the cache is only used when the component’s _parent_ is painting and is calling `paintComponentAndChildren` (opposite direction of what’s happening with the caret example).

Kind of, the key is that if a component is cached to an image then that image will be drawn instead of calling the component’s `paint()` method. The component’s `paint()` method will only ever be invoked if you invalidate the cache by explicitly calling `repaint()` on the component (or any other action that causes `repaint()` to be called for that component).

---

<div class="post-metadata">

**Author:** ![ImJimmi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/imjimmi/32/10843_2.png) [@ImJimmi](https://forum.juce.com/u/ImJimmi)\
**Post date:** [April 21, 2022, 10:06pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/10 "2022-04-21T22:06:22Z")

</div>

I had assumed that when a `CachedImageComponent` is drawn, it would only draw the portion of the image that overlaps with the clip region of the graphics context.

Looking at the implementation of `StandardCachedImageComponent`:

> <https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L843>

That doesn’t seem to be the case… meaning if you only needed to draw a single pixel of a cached image, it would draw the _entire_ image to the context, most of which would be ignored.

Unless I’m missing something, there’s an optimisation to be made there because drawing images is expensive so only drawing as few pixels as possible could be a huge improvement in some cases.

E.g. you could do something like:

```cpp
const auto clipBounds = g.getClipBounds();
const auto areaToDraw = imageBounds.getIntersection (clipBounds);
g.drawImage (image,
             clipBounds.getX(), clipBounds.getY(), clipBounds.getWidth(), clipBounds.getHeight(),
             areaToDraw.getX(), areaToDraw.getY(), areaToDraw.getWidth(), areaToDraw().getHeight(),
             true);

```

Maybe this is already handled within the graphics implementation of drawing an image? I don’t know.

You can actually supply your own `juce::CachedComponentImage` to a `juce::Component` where you can customise the behaviour of invalidating and updating the cache, if you really wanted.

---

<div class="post-metadata">

**Author:** ![jakemumu](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/jakemumu/32/13038_2.png) [@jakemumu](https://forum.juce.com/u/jakemumu)\
**Post date:** [April 22, 2022, 3:00am UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/11 "2022-04-22T03:00:10Z")

</div>

I assumed this was the case here as well - worth a test for sure!

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 22, 2022, 10:20am UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/12 "2022-04-22T10:20:38Z")

</div>

> [@ImJimmi](#):
>
> `setVisible()` will call `repaint()` on the component in question if it has just been made visible - if not it will call `repaint()` on the _parent_

Right, so in the case of the caret 🥕, every time it turns off via `setVisible`, repaint is called on the parent text editor, invalidating the `cachedImage`, telling the OS the entire text editor is dirty.

> [@ImJimmi](#):
>
> If you haven’t called `setBufferedToImage(true)` on the text editor, then every single time the caret’s made invisible, your _entire_ text editor is being rendered

I believe this happens regardless, due to the explicit call to repaint that `setVisible` makes — this is part of the behavior I wanted to override in the CaretComponent class…

> [@ImJimmi](#):
>
> When you call `repaint()` on a component, you’re not saying “please call `paint()` on this component at some point in the near future”. What you’re doing is first invalidating the cache, if the component on which `repaint()` was called is set to buffer to an image, then telling the _OS_ , “this portion of the screen needs to be redrawn on the next update please”.

This is a good summary! I might quote you / ask for your review on my next article on “How JUCE Components work” 😃

---

<div class="post-metadata">

**Author:** ![RolandMR](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/rolandmr/32/641_2.png) [@RolandMR](https://forum.juce.com/u/RolandMR)\
**Post date:** [April 22, 2022, 3:47pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/13 "2022-04-22T15:47:57Z")

</div>

When `Component::setVisible (false)` is called, it calls `repaint()` on the parent and when `repaint()` is called, it bubbles up the stack of components, calling `repaint()` on each one. This causes all the buffered images to get cleared, which seems to completely defeat the purpose of buffering to image. Seems like it’s only useful for the top level component. Seems like when you call repaint on a component, it should just map its bounds to the `ComponentPeer` and call repaint on that. Then the peer will call `paint()` bubbling up if needed or use the cached image.

I haven’t looked at the code a lot, maybe there is something I’m overlooking.

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 22, 2022, 4:24pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/14 "2022-04-22T16:24:48Z")

</div>

Hmmm, this stuff gets complicated. I’ve been thinking better clarification in the documentation would be helpful. Maybe a table for which methods call repaint, etc.

The best mental model I’ve found is “The OS paints top-down” through the component hierarchy and like you said, “repaint bubbles bottom up.”

> [@RolandMR](#):
>
> This causes all the buffered images to get cleared, which seems to completely defeat the purpose of buffering to image.

The `cachedImage`s should to [only invalidate the area of the child region as the repaint propagates upwards](https://github.com/juce-framework/JUCE/blob/develop/modules/juce_gui_basics/components/juce_Component.cpp#L1945-L1946). So, I think unless repaint() is called explicitly on the parent without bounds, the `cachedImage` stays useful?..

~~`setVisible` is a bit nasty in that it unconditionally calls repaint on the whole parent~~.

I was wrong about this, `repaintParent` is friendly and only invalidates the component’s bounds in the parent:

```c++
void Component::repaintParent()
{
    if (parentComponent != nullptr)
        parentComponent->internalRepaint (ComponentHelpers::convertToParentSpace (*this, getLocalBounds()));
}

```

Combining with what Jimmi pointed to:

> each component will draw itself and any of its children [_that overlap the portion of the screen marked for repainting_](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L2027).

My conclusion is that `setBufferedToImage` is useful for a component when :

1. The component + children are fairly expensive to create
2. Child components are at different discrete locations and might be painted at different times from each other
3. `repaint()` isn’t being manually called a lot on the component

So, anything that renders text seems does seem like a good candidate… 🥕

---

<div class="post-metadata">

**Author:** ![RolandMR](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/rolandmr/32/641_2.png) [@RolandMR](https://forum.juce.com/u/RolandMR)\
**Post date:** [April 22, 2022, 4:52pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/15 "2022-04-22T16:52:56Z")

</div>

Turns out I’ve never actually read the documentation for `setBufferedToImage` closely.

> Setting this flag to true will cause the component to allocate an internal buffer into which it paints itself and all its child components, so that when asked to redraw itself

I didn’t realize the children get added to the buffer as well. I assumed each Component got its own buffer and then they would just be blitted on top each other. This means setting `setBufferedToImage(true)` on a `TextEditor` is pretty much pointless, because the cursor blinking has to regenerate the image. Even if all the text isn’t being redraw, all the layout still needs to be redone and that is expensive. Maybe the `TextEditor` should cache its `GlyphArrangement`?

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 22, 2022, 4:56pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/16 "2022-04-22T16:56:06Z")

</div>

I think I might have confused myself a bit, I just updated my previous post. `setVisible(false)` (what the cursor does) actually calls `repaintParent` which supposedly only invalidates the cursor’s bounds in the cachedImage, I think?.. But my testing shows that the TextEditor’s paint method is called, so I’m a bit confused now.

---

<div class="post-metadata">

**Author:** ![RolandMR](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/rolandmr/32/641_2.png) [@RolandMR](https://forum.juce.com/u/RolandMR)\
**Post date:** [April 22, 2022, 5:00pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/17 "2022-04-22T17:00:51Z")

</div>

Yes, if a portion of the cached image is invalid, then it needs to be regenerated. So then TextEditor::paint is called to fill in a portion of the image.

---

<div class="post-metadata">

**Author:** ![sudara](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/sudara/32/8071_2.png) [@sudara](https://forum.juce.com/u/sudara)\
**Post date:** [April 22, 2022, 5:09pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/18 "2022-04-22T17:09:10Z")

</div>

Hmm then I don’t really understand the point of partial invalidation. Is there a way the cachedImage can still be used for other (valid) bounds? If we are currently painting a child, that means the parent has already been painted and has no more need for the cachedImage.

Ahhhh maybe this is where `isOpaque` comes in. [If the child is opaque, then the parent can remove those bounds, and it won’t intersect with what’s being considered “dirty” at paint time.](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L461)

---

<div class="post-metadata">

**Author:** ![parawave](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/parawave/32/5292_2.png) [@parawave](https://forum.juce.com/u/parawave)\
**Post date:** [April 22, 2022, 5:16pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/19 "2022-04-22T17:16:20Z")

</div>

I would call this thread “mildly interesting” because as a Windows 10 user I’m somewhat immune to jank. e.g. On all major browsers (Edge, Firefox, Chrome) you can’t even resize a window without lagging behind the surface area 😂

Never heard the term jank before. Sounds like a very broad term. I use these terms for visual unpleasant but non critical “problems”.

- **Jitter:** While resizing, a fixed layout or position jumps back and forth due to rounding or int casting.

- **Tearing:** Region updates split graphics in half due to disabled VSync or unsync repaints.

- **Frame Lag:** An otherwise smooth animation suddenly slows down. Often due to complex path rendering.

- **Artifacts:** Regions use memory, texture, image data that was not cleared and can possibly contain “anything” / noise.

- **Stutter:** A linear moving object (eg. at the rate of 1px per frame) seems to skip frames. Most often because of inaccurate frame timings.

- **Micro Stutter:** Using a variable timestep, objects moving on float coordinates seem to jump back and forth due to different delta time roundings.

- **Cracks:** Specific to GPU / Triangle rendering. Vertices that render on float coordinates introduce small pixel cracks on resize with non-uniform scales. Again due to rounding. Better to use a fixed resolution and scale with integer factors and render into a framebuffer instead.

- **Glitches:** Small repaint regions are not updated, resulting in pixel artifacts.

- **Blurry:** Non DPI aware implementations result in linear interpolated image textures. Often resulting in non anti aliases rectangle borders due to the hard polygon edges.

About the repaint() issue. During development/prototyping I recommend not using it at all. Same for setBufferedImage(). Later during testing you’ll eventually see outdated regions. The advantage: You avoid unnecessary repaints() and will eventually find a pattern where and when an update should happen. Most of the time it’s really just one function.

For OpenGL debugging I strongly recommend [https://renderdoc.org/](https://renderdoc.org/)  
It’s really amazing. You can capture frames and look at individual commands and preview every step of the frame constructions.

---

<div class="post-metadata">

**Author:** ![ImJimmi](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/imjimmi/32/10843_2.png) [@ImJimmi](https://forum.juce.com/u/ImJimmi)\
**Post date:** [April 22, 2022, 5:40pm UTC](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112/20 "2022-04-22T17:40:18Z")

</div>

> [@sudara](#):
>
> Hmm then I don’t really understand the point of partial invalidation.

When your components are being painted, you could check the clip bounds of the `juce::Graphics` object supplied and only draw elements that are within those bounds. For example if you had some text at the top of the component but only the bottom potion is drawn, yo could just skip drawing the text.

Although I find a better approach for this is to simply have child components to draw each element of a more complex component so you get this sort of behaviour already.

> [@sudara](#):
>
> Ahhhh maybe this is where `isOpaque` comes in. [If the child is opaque, then the parent can remove those bounds, and it won’t intersect with what’s being considered “dirty” at paint time.](https://github.com/juce-framework/JUCE/blob/2f980209cc4091a4490bb1bafc5d530f16834e58/modules/juce_gui_basics/components/juce_Component.cpp#L461)

Yeah, if you call `setOpaque (true)` on a component then any components behind it won’t need to be repainted since you’ve said the opaque component will draw to the full area.

[Next page](https://forum.juce.com/t/i-wrote-a-bit-about-jank-in-juce/51112.md?page=2)
