Resizing/Scaling issues in Ableton VST3 with Hi-DPI resolution on Windows

Hello JUCE Team,

We’re having strange resizing issues in Ableton Live 10 VST3 on Windows using a Hi-DPI machine. Everything works as expected when calling setSize() using a standard TextButton but when the same function is called from a popup menu, the plugin host window resizes incorrectly. Please find attached a gif demonstrating the issue with a basic JUCE Audio Plugin project built from the latest master. It uses the OpenGL renderer but the issue is still present with the default rendering pipeline. Thanks for your help!

Here’s the code from the demo:

PluginEditor.h

/*
  ==============================================================================

    This file was auto-generated!

    It contains the basic framework code for a JUCE plugin editor.

  ==============================================================================
*/

#pragma once

#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"

//==============================================================================
/**
*/
class TestPluginAudioProcessorEditor  : public AudioProcessorEditor,
										private OpenGLRenderer
{
public:
    TestPluginAudioProcessorEditor (TestPluginAudioProcessor&);
    ~TestPluginAudioProcessorEditor();

    //==============================================================================
    void paint (Graphics&) override;
    void resized() override;

	void newOpenGLContextCreated() override;
	void renderOpenGL() override;
	void openGLContextClosing() override;

private:
	OpenGLContext m_openGLContext;
	TextButton popupButton{ "Change Window Size Via Popup" };
	TextButton randomButton{ "Change Window Size Randomly" };
	Component m_all;

	void makePopup();

	static void popupMenuFishedCallback(int v, TestPluginAudioProcessorEditor* editor) 
	{
		editor->setUIScale(v);
	}

	void setUIScale(int v)
	{
		setSize(400 * v, 300 * v);
	}

    // This reference is provided as a quick way for your editor to
    // access the processor object that created it.
    TestPluginAudioProcessor& processor;

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TestPluginAudioProcessorEditor)
};

PluginEditor.cpp

/*
  ==============================================================================

    This file was auto-generated!

    It contains the basic framework code for a JUCE plugin editor.

  ==============================================================================
*/

#include "PluginProcessor.h"
#include "PluginEditor.h"

//==============================================================================
TestPluginAudioProcessorEditor::TestPluginAudioProcessorEditor (TestPluginAudioProcessor& p)
    : AudioProcessorEditor (&p), processor (p)
{
	setResizable(false, false);

	m_openGLContext.setOpenGLVersionRequired(OpenGLContext::OpenGLVersion::openGL3_2);
	m_openGLContext.setRenderer(this);
	m_openGLContext.setMultisamplingEnabled(true);

	OpenGLPixelFormat format;
	format.multisamplingLevel = 8;
	m_openGLContext.setPixelFormat(format);

	// Attach OpenGL and start graphics timer
	m_openGLContext.attachTo(*this);

	// Add popup button
	addAndMakeVisible (popupButton);
	popupButton.onClick = [this] { makePopup(); };
	popupButton.setBounds(20, 20, 200, 40);
	m_all.addAndMakeVisible(&popupButton);

	// add random button
	addAndMakeVisible(randomButton);
	randomButton.onClick = [this] { setUIScale(rand() % 3 + 1); };
	randomButton.setBounds(20, 80, 200, 40);
	m_all.addAndMakeVisible(&randomButton);

	m_all.setBounds(0, 0, 400, 300);

	addAndMakeVisible(&m_all);

    setSize (400, 300);
}

TestPluginAudioProcessorEditor::~TestPluginAudioProcessorEditor()
{
	m_openGLContext.detach();
}

//==============================================================================
void TestPluginAudioProcessorEditor::paint (Graphics& g)
{
    // (Our component is opaque, so we must completely fill the background with a solid colour)
    g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
}

void TestPluginAudioProcessorEditor::resized()
{
	auto r = getLocalBounds();

	float scale = float(r.getWidth()) / 400.f;

	auto transform = AffineTransform().scale(scale);

	m_all.setTransform(transform);
}

void TestPluginAudioProcessorEditor::newOpenGLContextCreated() {}
void TestPluginAudioProcessorEditor::renderOpenGL() {}
void TestPluginAudioProcessorEditor::openGLContextClosing() {}

void TestPluginAudioProcessorEditor::makePopup()
{
	PopupMenu popup;

	popup.addItem(1, "Small", true, false);
	popup.addItem(2, "Medium", true, false);
	popup.addItem(3, "Large", true, false);

	popup.showMenuAsync(PopupMenu::Options()
		.withTargetComponent(&popupButton)
		.withItemThatMustBeVisible(0)
		.withMaximumNumColumns(1)
		.withStandardItemHeight(22.f),
		ModalCallbackFunction::forComponent(popupMenuFishedCallback, this));
}

Thanks for reporting. Can you see if this commit fixes the problem for you?

Unfortunately, the fix doesn’t change anything on our side. Were you able to replicate the issue with the code provided?

Before the change above, the test code that you provided was resizing incorrectly similar to your screencap when using the popup - the host window was the wrong size and the buttons were rendered at the wrong scale. Adding that check seems to have fixed things for me and the size and rendering are now correct when changing the size via either method. Have you done a clean build so you’re sure that Live is loading the latest version of the plug-in?

We’ve tested on the tip of develop with a clean build on two different Windows machines but to no avail. We can confirm the debugger steps through the additional call to setBounds() but the host window size and buttons are still rendered incorrectly.

Hmm. Which version of Live are you using? I’m testing with the latest 10.1.2b5 beta.

Maybe it has to do with the Windows system HiDpi scaling factor? For a test plugin I’m using - it shows pixelated (no hidpi), while the main Ableton window is not, and also similar weird things happen when setTransform is called. Dragging the window around in Ableton also triggers some things that would resize it.

We were using the latest release. If we switch to the latest beta (10.1.2 b7) the fix does seem to work.