dpolito
February 19, 2025, 6:06pm
21
a quick pass at this idea is promising
here is my ui before resize
during resize
after resize
ignore the fact that my components are gone. I need to do some reinitialization on my end.
as you can see the image just gets resampled down when scaling which is okay… better than jittering? it would suck with resizing upward obviously. My current issue is that some of my components dont get captured. I expect that’s because my render pipeline doesn’t necessarily include all things in the juce::Component tree so that’s a me specific problem.
I implemented this by extending the juce::ComponentBoundsConstrainer and overriding ‘resizeStart’ ‘resizeEnd’ and ‘checkBounds’.
void BorderBoundsConstrainer::resizeStart() {
if (gui_)
{
const auto imageToUse = [&]() -> juce::Image
{
const auto scaleFactor = 2.0;
auto image = gui_->createComponentSnapshot (gui_->getBounds(), false, 1)
.convertedToFormat (juce::Image::ARGB);
return { image };
}();
if (!gui_->resize_image_.isValid())
gui_->resize_image_ = imageToUse;
gui_->open_gl_context_.detach();
gui_->enableRedoBackground(false);
gui_->resizing = true;
}
}
void BorderBoundsConstrainer::resizeEnd() {
if (gui_) {
//LoadSave::saveWindowSize(gui_->getWidth() / (1.0f * vital::kDefaultWindowWidth));
gui_->open_gl_context_.setContinuousRepainting(true);
gui_->open_gl_context_.setOpenGLVersionRequired(juce::OpenGLContext::openGL3_2);
gui_->open_gl_context_.setSwapInterval(0);
gui_->open_gl_context_.setRenderer(gui_);
//componentpaintingenabled fixes flickering
gui_->open_gl_context_.setComponentPaintingEnabled(false); // set to true, and the non-OpenGL components will draw
gui_->open_gl_context_.attachTo(*gui_);
gui_->resize_image_ = juce::Image();
gui_->resizing = false;
}
}
void BorderBoundsConstrainer::checkBounds(juce::Rectangle<int>& bounds, const juce::Rectangle<int>& previous,
const juce::Rectangle<int>& limits,
bool stretching_top, bool stretching_left,
bool stretching_bottom, bool stretching_right) {
border_.subtractFrom(bounds);
double aspect_ratio = getFixedAspectRatio();
juce::ComponentBoundsConstrainer::checkBounds(bounds, previous, limits,
stretching_top, stretching_left,
stretching_bottom, stretching_right);
...
gui_->resize_image_ = gui_->resize_image_.rescaled(bounds.getWidth(), bounds.getHeight(),juce::Graphics::ResamplingQuality::highResamplingQuality)
...
}
dpolito
February 19, 2025, 10:02pm
22
doing some debugging and just confirming what you said here.
wondering if there could be a way to synchronize on our side from the resize call.
Thread0x16bc47000Function: renderAll full_interface 0 0 1400 820
Thread0x16bc47000Function: renderOpenGL 0 0 1400 820
Thread0x16bc47000Function: renderAll full_interface 0 0 1400 820
Thread0x16bc47000Function: renderOpenGL 0 0 1400 820
Thread0x16bc47000Function: renderAll full_interface 0 0 1400 820
Thread0x1ea1e0240Function: resized 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x1ea1e0240Function: handleResize full_interface 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
2025-02-19 16:52:10.060910-0500 bitKlavier2 Demo[54218:8845805] Unable to open mach-O at path: default.metallib Error:2
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x16bc47000Function: renderOpenGL 0 0 1376 806
Thread0x16bc47000Function: renderAll full_interface 0 0 1376 806
Thread0x1ea1e0240Function: resized 0 0 1252 733
Thread0x16bc47000Function: renderOpenGL 0 0 1252 733
Thread0x1ea1e0240Function: handleResize full_interface 0 0 1252 733
this isn’t the best formatting for my prints but resized is in my code at the top level so it gets called on one thread before the handleResize which is juce openglcontext code and that gets called on the same thread but not until all the components have been resized. You can see we end up rendering at least a frame with the new size before the the actual Mac app components get updated.
1 Like
aamf
February 22, 2025, 1:44am
23
Hi there, I’m doing the same, using the ComponentBoundsConstrainer and suspending the rendering while resizing. I am not using createComponentSnapshot() though, but instead when resizing begins I capture the main framebuffer onto a texture and from then on only render that texture and return. Seems to work (or at least help) but only if component painting is enabled. This is of course a hack but anything is better than the jittering!
dpolito
February 26, 2025, 9:13pm
24
Oh that’s smart. How does it work with resizing up?
Also how do you capture the main framebuffer lol
Unfortunately I have component painting off. I guess I could overwrite all the component paint methods to do nothing if I wanted to use this.
aamf
March 3, 2025, 7:12pm
25
If resizing by a lot the image looks quite blurry, but I think it looks better than the jittering.
This is in essence what I’m doing:
GLuint frozenTexture = 0;
void initializeFrameCapture()
{
if (frozenTexture == 0)
glGenTextures(1, &frozenTexture);
glBindTexture(GL_TEXTURE_2D, frozenTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, componentWidth * renderingScale,
componentHeight * renderingScale,
0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
}
void captureFramebuffer()
{
GLint fboInt;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fboInt);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboInt);
glBindTexture(GL_TEXTURE_2D, frozenTexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, componentWidth * renderingScale,
componentHeight * renderingScale);
glBindTexture(GL_TEXTURE_2D, 0);
}
When resizing begins I call captureFramebuffer() at the end of the render callback and then while resizing I render frozenTexture as a full-screen quad.
1 Like